抱歉非技术标题,但我认为它很好地总结了我的问题。如果我正确解释了我读到的内容,同步块(synchronized block)(除了其他后果)将使所有变量更新到/从主内存(即使是那些没有在同步块(synchronized block)内显式访问的变量,只有它们的“父”?) .例如。引用 this 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()
和 operationA()
是从 ThreadA 调用的。 (注意 initA()
甚至在创建 ThreadB 之前被调用,所以只有 getterB()
和 operationA()
是并发的。)另外请注意,我有一个很好的理由不在 getterB()
中返回数组的副本(不,threadB 不想改变它的元素;原因是我的软件的外部需求现在不相关)。threadB 这样做:
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
引用,而不是数组值本身。我的问题:getterB()
的主内存中更新?) 我不是 100% 如何解释这个无关的(与用于锁定的变量无关?或与整个同步块(synchronized block)无关?)。我知道我断章取意了,因为这是一个不同的计算器问题,我添加了评论 there 。所以我很感激我的问题是否在那里(或在这里 - 我不在乎)得到解答。
anArray
是一个对象数组(而不是原始类型),答案有什么不同吗?更进一步,如果它不是一个数组,而是一个包含对其他类的引用的类呢? (即引用其他对象的对象,我通过 getterB()
返回的对象访问包含的对象)。 threadB 会使用这些包含的引用 的最新副本,还是可以使用它自己的本地缓存副本(因为 getterB()
只更新了它们的容器对象,而不是包含的引用本身)?。 最佳答案
按顺序回答你的问题:
operationA()
修改的所有值在 getterB()
的结果引用的数组中都是“最新的”。 最后,只是一个评论,因为
getterB()
不返回数组的副本,因此我会非常警惕上面总结的代码。我知道您有理由以上述方式进行操作(并且您不想要这种反馈!),但是您应该确保了解 B
上的线程 anArray
中的所有“各种操作” getterB()
返回后发生的情况将不 protected 。 (换句话说,在此期间对线程 A
上的数组所做的任何更改都会带来危险。)避免低效深数组复制的一种替代方法是将这些“各种操作”移动到新方法中的同步块(synchronized block)中在 SomeClass
中并完全摆脱 getterB()
。当然,我意识到代码中的“正确解决方案”取决于此处未显示的许多内容,因此请随意忽略这一点。关于java - 同步块(synchronized block) : are variables "inside" other variables updated,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/11278476/