很抱歉这个非技术性的标题,但我认为它很好地总结了我的问题。如果我正确解释了我读过的内容,同步块(除了其他后果)将使所有变量更新到主内存/从主内存更新(即使是那些在同步块内没有显式访问的变量,只有它们的“父”?) . 例如引用这个stackoverflow问题的答案(我把它断章取意,我稍后会回到它):
内存屏障适用于所有内存引用,甚至是不相关的内存引用。
我需要确认我是否正确解释了这一点。我有 2 个线程(线程 A、线程 B)。考虑以下代码:
public class SomeClass {
private final Object mLock = new Object();
private int[] anArray;
public void initA() {
synchronized(mLock) {
...
anArray = new int[...];
operationA();
}
}
public void operationA() {
synchronized(mLock) {
// Manipulating the ELEMENTS of anArray,
// e.g. in loops, etc.
anArray[i] = ...
}
}
public int[] getterB() {
synchronized(mLock) {
return anArray;
}
}
}
getterB()
从ThreadB调用,从initA()
ThreadA调用。(请注意,甚至在创建ThreadB之前调用它,因此只有和是并发的。)还要注意,我有充分的理由不返回数组的副本(不,threadB不想更改其元素;原因是我的软件的外部要求,现在不相关)。operationA()
initA()
getterB()
operationA()
getterB()
线程B这样做:
int[] anArray = aSomeClass.getterB(); // aSomeClass is an instance of SomeClass
if (anArray[i] == n) { ....... } // various operations
...
// various other operations that read the elements of anArray
如您所见,在内存屏障中getterB()
仅anArray
访问引用,而不是数组值本身。我的问题:
threadB 会看到最新的数组元素值吗?(即元素本身是否也从主内存更新
getterB()
?)引用的声明提到不相关的缓存副本也从主内存更新。我不是 100% 如何解释这个不相关的(与用于锁定的变量无关?或与整个同步块无关?)。我知道我把引用断章取义了,因为这是一个不同的 stackoverflow 问题,所以我在那里添加了评论。所以我很感激我的这个问题是否在那里(或这里——我不在乎)得到了回答。
anArray
如果是对象数组(而不是原始类型),答案有什么不同吗?更进一步,如果它不是一个数组,而是一个包含对其他类的引用的类怎么办?(即引用其他对象的对象,我通过返回的对象访问包含的对象getterB()
)。threadB 会使用 这些包含引用的最新副本,还是使用它自己的本地缓存副本(因为getterB()
只更新了它们的容器对象,而不是包含的引用本身)?