简体   繁体   English

同步和可见范围

[英]Synchronized and the scope of visibility

I've been reading up on Java concurrency and had forgot the fact that synchronization blocks in two threads using the same lock also affect the visibility of variables, even though they were not defined as "volatile".我一直在阅读 Java 并发性,却忘记了使用相同锁的两个线程中的同步块也会影响变量的可见性,即使它们没有被定义为“易失性”。 If I have code like this如果我有这样的代码

Object lock = new Object();
boolean a = false, b = false, c = false;

void threadOne() {

   a = true;
   synchronized(lock) {
      b = true;
   }
   c = true;

}

void threadTwo() {

   while (true) {
      synchronized(lock) {
         if (a && b && c) break;
      }
   } 

}

... and threadOne and threadTwo will be called by different threads: ...并且 threadOne 和 threadTwo 将被不同的线程调用:

  1. Is it guaranteed that the code will break out of the while loop?是否保证代码会跳出while循环?

  2. What if we remove variable c out of the equation?如果我们从方程中删除变量 c 怎么办? I'm wondering if only b is guaranteed to be visible in threadTwo because it was inside the synchronization block.我想知道是否只有 b 保证在 threadTwo 中可见,因为它在同步块内。

Is it guaranteed that the code will break out of the while loop?是否保证代码会跳出while循环?

No. The Java memory model is defined in terms of " happens before " relationships:不,Java 内存模型是根据“ 发生在”关系定义的:

Two actions can be ordered by a happens-before relationship.两个动作可以通过happens-before关系排序。 If one action happens-before another, then the first is visible to and ordered before the second.如果一个动作发生在另一个动作之前,那么第一个动作对第二个动作可见并在第二个动作之前排序。

The spec goes on to say:规范继续说:

If an action x synchronizes-with a following action y, then we also have hb(x, y).如果动作 x 与后续动作 y 同步,那么我们也有 hb(x, y)。

where hb stands for happens-before, and其中hb代表发生在之前,并且

An unlock action on monitor m synchronizes-with all subsequent lock actions on m (where "subsequent" is defined according to the synchronization order).监视器 m 上的解锁操作与 m 上的所有后续锁定操作同步(其中“后续”根据同步顺序定义)。

Also note that:另请注意:

If hb(x, y) and hb(y, z), then hb(x, z).如果 hb(x, y) 和 hb(y, z),则 hb(x, z)。

So in your example, the synchronized(lock) around b will establish a happens-before relationship for the following read, and thus the value of b is guaranteed to be visible in other threads that also use synchronized(lock) .因此,在您的示例中, b周围的synchronized(lock)将为以下读取建立先发生关系,因此b的值保证在也使用synchronized(lock)的其他线程中可见。 Explicitly,明确地说,

hb(write to b in threadOne, unlock in threadOne) AND 
hb(unlock in threadOne, lock in threadTwo) AND 
hb(lock in threadTwo, read from a in threadTwo) IMPLIES 
hb(write to b in threadOne, read from b in threadTwo) 

Similarly, a will be guaranteed to be visible to the other thread.同样,将保证a对其他线程可见。 Explicitly,明确地说,

hb(write to a in threadOne, lock in threadOne) AND 
hb(lock in threadOne, unlock in threadOne) AND 
hb(unlock in threadOne, lock in threadTwo) AND 
hb(lock in threadTwo, read a in threadTwo) IMPLIES 
hb(write to a in threadOne, read a in threadTwo). 

The write and then subsequent read of c does not have a happens-before relationship, so therefore, according to the spec, the write to c is not necessarily visible to threadTwo . c的写入和随后的读取没有发生之前的关系,因此,根据规范,对c的写入不一定对threadTwo可见。

What if we remove variable c out of the equation?如果我们从方程中删除变量 c 怎么办? I'm wondering if only b is guaranteed to be visible in threadTwo because it was inside the synchronization block.我想知道是否只有 b 保证在 threadTwo 中可见,因为它在同步块内。

Yes, see above.是的,见上文。

假设每个线程共享您在问题中定义的(不完整)类的相同实例:

是否保证代码会跳出while循环?

<\/blockquote>

在实践中,是的。锁只在 threadOne 方法中设置 b 的时间很短。 threadTwo 中有足够的上下文切换,以便 threadOne 能够执行同步块。 “在实践中”的含义:在极不可能的情况下(以及实施不佳的 JVM 线程),threadOne 可能会被排除在同步块之外,而 threadTwo 继续为 if 检查重新获取同步锁。<\/em> (事实上​​,我挑战任何人来制作一个 OPs 场景没有完成的工作示例)。

如果我们从方程中删除变量 c 怎么办?我想知道是否只有 b 保证在 threadTwo 中可见,因为它在同步块内。

<\/blockquote>

相同的。在实践中,是的。

对于额外的功劳(挑战),找到一个执行以下代码的 JVM,这样它就不会终止:

 public class SyncTest { public static void main(String args[]) throws Exception { final Shared s = new Shared(); Thread t1 = new Thread () { public void run() { s.threadOne(); } }; Thread t2 = new Thread () { public void run() { s.threadTwo(); } }; t2.start(); t1.start(); } } class Shared { Object lock = new Object(); boolean a = false, b = false, c = false; void threadOne() { a = true; synchronized(lock) { b = true; } c = true; } void threadTwo() { while (true) { synchronized(lock) { if (a && b && c) break; } } } }<\/code><\/pre>"

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM