3

我需要一些帮助来理解 Java 内存模型。以下是掌握基本概念的通用示例:

图片我有一个名为的对象实例Shared和两个线程AB. 此外,还有某种Queue带有同步puttake.

线程在方法之前和方法中A修改Shared-instance 。put

问题1:通过同步方法获取-object实例时,所有的变化A都是可见的吗?BSharedtake

Shared问题2:一旦A离开同步方法,内存缓存就会被刷新(所有更改都是可见的) put。如果在- 方法wait()中被调用,会发生什么?即使尚未退出- 方法,也会看到所做的更改?调用时缓存是否也被刷新?putABSharedAsynchronizedwait()

4

3 回答 3

4

答案 1:是的。因为 take() 和 put() 都是同步的。所以在 B 可以执行 take() 之前,A 应该已经离开了同步块,离开同步块意味着刷新内存缓存(内存栅栏/屏障)。

答案 2:是的。因为当调用 wait() 时,线程必须交出锁,这将再次导致内存刷新。

编辑:我认为您所追求的是缓存写入内存是否发生在同步块退出或锁定释放时。答案是cache-write-to-memory 在 lock 释放时发生

于 2011-11-26T14:42:20.373 回答
2

第一个问题的答案是肯定的,因为同步点(存在于 put 和 take 中)引入了隐式内存栅栏。

对于第二个问题,这取决于 A 调用是在对象添加到之前还是之后等待Shared。如果是之前,那么显然 shared 没有变化,所以 B 没有什么新东西可看。

编辑:如果 A 调用之后等待,则更改是可见的,因为您必须在添加之前获取锁,然后在等待时释放它,这也引入了栅栏。

所以在这两种情况下答案都是肯定的。

于 2011-11-26T14:40:37.643 回答
2

A 还没有退出同步方法?调用 wait() 时是否也会刷新缓存?

引用JSR 133(Java 内存模型)常见问题解答-同步有什么作用?

退出同步块后,我们释放监视器,这具有将缓存刷新到主内存的效果,以便该线程进行的写入可以对其他线程可见。在我们进入同步块之前,我们获取了监视器,它具有使本地处理器缓存无效的效果,以便从主内存重新加载变量。然后,我们将能够看到以前版本可见的所有写入。

它说在释放监视器时将缓存刷新到内存。请注意,当监视器在退出同步块时被释放时,它也会在调用等待方法时被释放。因此,我希望更改在 #wait() 调用上被刷新,并被另一个线程拾取,前提是它在同一监视器上稍早等待。

于 2011-11-26T15:01:11.883 回答