很抱歉非技术名称,但我认为它很好地总结了我的问题。如果我解释了我正确阅读的内容,同步块(除了其他后果)将使所有变量更新到主存储器(或者从同步块内未明确访问的那些变量,只有它们的“父”?) 。例如。引用this stackoverflow问题的答案(我把它脱离了上下文,我稍后会再回过头来):
内存屏障适用于所有内存引用,甚至是不相关的内存引用。
我是否需要确认是否正确解释了这一点。我有2个线程(threadA,threadB)。请考虑以下代码:
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;
}
}
}
从 ThreadB 调用 getterB()
,从{em> ThreadA 调用initA()
和operationA()
。 (请注意,即使在创建 ThreadB 之前,也会调用initA()
,因此只有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
引用,而不是数组值本身。我的问题:
threadB 会查看最新的数组元素值吗? (即元素本身是否也从getterB()
中的主内存更新?)
引用声明提到无关的缓存副本也会从主内存更新。 我不是100%如何解释这个无关的(与用于锁定的变量无关?或与整个同步块无关?)。我知道我把这个引用脱离了上下文,因为它是一个不同的stackoverflow问题,我添加了一条评论there。所以,如果我的问题得到解答(或者在这里 - 我不在乎),我感激不尽。
如果anArray
是一个对象数组(而不是原始类型),答案是否有任何不同?更进一步,如果它不是一个数组,而是一个包含对其他类的引用的类呢? (即引用其他对象的对象,我通过getterB()
返回的对象访问包含的对象)。 threadB 会使用这些包含的引用的最新副本,还是可以使用自己的本地缓存副本(因为getterB()
只更新了它们的容器对象,但不包含引用本身)?。
答案 0 :(得分:4)
按顺序提出问题:
是的:您可以放心地假设从operationA()
的结果引用的数组中所有已修改的值getterB()
中的所有值都是“最新的”
我会在另一个链接中回答这个问题;我承认我还没看过那个链接。但我的理解是,当你进入和退出同步块时,所有挂起的内存回写将“有效”发生(尽管这是如何发生的细节 - 即效率,以及是否有更多的缓存/流水线“技巧”继续以这种方式出现 - 取决于硬件和编译器)。如果您想了解更多有关此内容的详细信息,我发现此链接很有用:http://www.infoq.com/articles/memory_barriers_jvm_concurrency
不,没有区别(考虑到我在答案2中写的内容)。
最后,由于getterB()
没有返回数组副本这一事实,我只是对上面概述的代码非常警惕。我知道你有理由以上述方式这样做(并且你不想要这种反馈!),但是你应该确保理解线程{{1}中的所有“各种操作”在B
返回后发生的anArray
上的}将不受保护。 (换句话说,在此期间对线程getterB()
上的数组所做的任何更改都会有危险。)避免低效深度数组复制的另一种方法是在同步块中移动这些“各种操作”在A
中的新方法中,完全摆脱SomeClass
。当然,我意识到代码中的“正确解决方案”依赖于此处未显示的许多内容,因此请随意忽略这一点。