synchronized/volatile 在 Java 中的可变可见度影响范围是多少
What is the extent of variable visibility effect of synchronized/volatile in Java
根据"Java Concurrency in Practice":
everything A did in or prior to a synchronized block is visible to B when it executes a synchronized block guarded by the same lock
和
The visibility effects of volatile variables extend beyond the value of the volatile variable itself. When thread A writes to a volatile variable and subsequently thread B reads that same variable, the values of all variables that were visible to A prior to writing to the volatile variable become visible to B after reading the volatile variable
我不清楚的是 everything 和 是什么意思所有变量?它真的意味着一切吗?如果我们有这样的 class:
class MyClassA{
int a;
int[] array = new int[10];
MyClassB myClass; // a class with similar properties
void notSyncronizedMethod(){
// do something with a, array[3], myClass.a, myClass.array[3]
}
syncronized void syncronizedMethodA(){
// update value of a, array[3], myClass.a, myClass.array[3]
}
syncronized void syncronizedMethodB(){
// do something with a, array[3], myClass.a, myClass.array[3]
}
}
如果我们在一个线程中调用syncronizedMethodA()
,然后在另一个线程中调用syncronizedMethodB()
或notSyncronizedMethod()
,假设时间顺序是严格保证的,将调用syncronizedMethodB()
notSyncronizedMethod()
使用 syncronizedMethodA()
设置的最新变量值。我确定 a 的值对于 syncronizedMethodB()
是可以的,但是像 array[3]、myClass.a 甚至 myClass.myClass.array[3] 这样的引用类型的元素呢?如果 notSyncronizedMethod()
的值是通过同步方法更新的呢?
为了弄清楚提供了哪些可见性保证,您需要更好地理解 Java 内存模型,更具体地说,在 JMM 上下文中 happens-before 意味着什么。 JMM 将发生的事情描述为 操作 ,例如,正常读取和写入、可变读取和写入、锁定、解锁等
JMM 中有一些 rules 确定一个动作何时发生在另一个动作之前。与您的情况相关的规则如下:
单线程规则:在给定线程中,如果 A 在程序顺序中先于 B,则操作 A 发生在操作 B 之前。
监视器锁定规则(同步):给定监视器的解锁发生在同一监视器上的后续锁定之前。
重要的是要知道 happens-before 是传递性的,即如果 hb(a, b) 和 hb(b, c),则 hb(a, c)。
在您的示例中,一个线程在退出 syncronizedMethodA()
时释放监视器,而另一个线程随后在进入 syncronizedMethodB()
时获取监视器。那是一种先发生后关系。由于 HB 是可传递的,因此在 syncronizedMethodA()
中执行的操作对于随后进入 syncronizedMethodB()
.
的任何线程都是可见的
另一方面,syncronizedMethodA()
中监视器的释放与另一个线程在 notSynchronizedMethod()
中执行的后续操作之间不存在先行关系。因此,无法保证 syncronizedMethodA()
中的写入对另一个线程在 notSynchronizedMethod()
中的读取可见。
根据"Java Concurrency in Practice":
everything A did in or prior to a synchronized block is visible to B when it executes a synchronized block guarded by the same lock
和
The visibility effects of volatile variables extend beyond the value of the volatile variable itself. When thread A writes to a volatile variable and subsequently thread B reads that same variable, the values of all variables that were visible to A prior to writing to the volatile variable become visible to B after reading the volatile variable
我不清楚的是 everything 和 是什么意思所有变量?它真的意味着一切吗?如果我们有这样的 class:
class MyClassA{
int a;
int[] array = new int[10];
MyClassB myClass; // a class with similar properties
void notSyncronizedMethod(){
// do something with a, array[3], myClass.a, myClass.array[3]
}
syncronized void syncronizedMethodA(){
// update value of a, array[3], myClass.a, myClass.array[3]
}
syncronized void syncronizedMethodB(){
// do something with a, array[3], myClass.a, myClass.array[3]
}
}
如果我们在一个线程中调用syncronizedMethodA()
,然后在另一个线程中调用syncronizedMethodB()
或notSyncronizedMethod()
,假设时间顺序是严格保证的,将调用syncronizedMethodB()
notSyncronizedMethod()
使用 syncronizedMethodA()
设置的最新变量值。我确定 a 的值对于 syncronizedMethodB()
是可以的,但是像 array[3]、myClass.a 甚至 myClass.myClass.array[3] 这样的引用类型的元素呢?如果 notSyncronizedMethod()
的值是通过同步方法更新的呢?
为了弄清楚提供了哪些可见性保证,您需要更好地理解 Java 内存模型,更具体地说,在 JMM 上下文中 happens-before 意味着什么。 JMM 将发生的事情描述为 操作 ,例如,正常读取和写入、可变读取和写入、锁定、解锁等
JMM 中有一些 rules 确定一个动作何时发生在另一个动作之前。与您的情况相关的规则如下:
单线程规则:在给定线程中,如果 A 在程序顺序中先于 B,则操作 A 发生在操作 B 之前。
监视器锁定规则(同步):给定监视器的解锁发生在同一监视器上的后续锁定之前。
重要的是要知道 happens-before 是传递性的,即如果 hb(a, b) 和 hb(b, c),则 hb(a, c)。
在您的示例中,一个线程在退出 syncronizedMethodA()
时释放监视器,而另一个线程随后在进入 syncronizedMethodB()
时获取监视器。那是一种先发生后关系。由于 HB 是可传递的,因此在 syncronizedMethodA()
中执行的操作对于随后进入 syncronizedMethodB()
.
另一方面,syncronizedMethodA()
中监视器的释放与另一个线程在 notSynchronizedMethod()
中执行的后续操作之间不存在先行关系。因此,无法保证 syncronizedMethodA()
中的写入对另一个线程在 notSynchronizedMethod()
中的读取可见。