抱歉非技术标题,但我认为它很好地总结了我的问题。如果我正确解释了我读到的内容,同步块(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 引用,而不是数组值本身。我的问题:
  • threadB 会看到最新的数组元素值吗? (即元素本身是否也从 getterB() 的主内存中更新?)
  • 引用的语句提到 无关的 缓存副本也从主内存更新。
    我不是 100% 如何解释这个无关的(与用于锁定的变量无关?或与整个同步块(synchronized block)无关?)。我知道我断章取意了,因为这是一个不同的计算器问题,我添加了评论 there 。所以我很感激我的问题是否在那里(或在这里 - 我不在乎)得到解答。
  • 如果 anArray 是一个对象数组(而不是原始类型),答案有什么不同吗?更进一步,如果它不是一个数组,而是一个包含对其他类的引用的类呢? (即引用其他对象的对象,我通过 getterB() 返回的对象访问包含的对象)。 threadB 会使用这些包含的引用 的最新副本,还是可以使用它自己的本地缓存副本(因为 getterB() 只更新了它们的容器对象,而不是包含的引用本身)?。
  • 最佳答案

    按顺序回答你的问题:

  • 是:您可以安全地假设从任何先前调用的 operationA() 修改的所有值在 getterB() 的结果引用的数组中都是“最新的”。
  • 我会在另一个链接中回答这个问题;我承认我还没有阅读那个链接。但我的理解是,当您进入和退出同步块(synchronized block)时,所有挂起的内存回写都将“有效”发生(尽管这是如何发生的细节——即效率,以及是否有更多的缓存/流水线“技巧”继续使其出现这种方式 - 将取决于硬件和编译器)。如果你想了解更多细节,我曾经发现这个链接很有用:http://www.infoq.com/articles/memory_barriers_jvm_concurrency
  • 不,没有区别(鉴于我在答案 2 中写的内容)。

  • 最后,只是一个评论,因为 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/

    10-12 04:29