我需要一些帮助来理解Java内存模型。以下是掌握基本概念的一个通用示例:
图片我有一个名为Shared
的对象实例和两个线程A
和B
。此外,某种Queue
还有同步put
和take
。
线程A
修改Shared
- 实例之前和 put
方法。
问题1:当A
通过同步B
方法获取Shared
- 对象实例时,{{1>}的所有更改都会显示?
问题2:只要take
离开同步Shared
方法,内存缓存就会被刷新(A
上的所有更改都可见)。如果在put
方法中调用wait()
put
,会发生什么样的事情?即使A
尚未退出B
方法,Shared
也会看到对A
所做的更改吗?调用synchronized
时是否刷新缓存?
答案 0 :(得分:4)
回答1 :是的。因为take()和put()都是同步的。所以在B可以执行take()之前,A应该离开synchronized块并且保持synchronized块意味着刷新内存缓存(内存栅栏/屏障)。
回答2 :是的。因为当调用wait()时,线程必须放弃锁定,这将再次导致内存刷新。
编辑:我认为你所追求的是在退出同步块或释放锁定时是否发生缓存写入内存。答案是在释放锁定时发生缓存写入内存。答案 1 :(得分:2)
您的第一个问题的答案是肯定的,因为同步点(存在于put和take中)会引入隐式内存栅栏。
对于第二个问题,它取决于A调用在对象添加到Shared
之前或之后等待。如果它在之前,那么显然共享没有变化,所以B没有什么新东西可以看。
编辑:如果A调用等待,则更改是可见的,因为您必须在添加之前获取锁定,然后在等待时释放它,这也会引入围栅。
所以答案都是肯定的。
答案 2 :(得分:2)
A尚未退出同步方法?调用wait()时缓存是否也刷新了?
引自JSR 133 (Java Memory Model) FAQ - What does synchronization do?:
在我们退出synchronized块之后,我们释放了监视器,它具有将缓存刷新到主内存的效果,因此该线程所做的写操作对其他线程是可见的。在我们进入同步块之前,我们获取监视器,它具有使本地处理器高速缓存无效的效果,以便从主存储器重新加载变量。然后,我们将能够看到前一版本中显示的所有写入。
它表示在释放监视器时会将缓存刷新到内存。请注意,虽然在退出同步块时释放监视器,但在调用wait方法时也会释放它。因此,我希望在#wait()调用中刷新更改并由另一个线程获取,前提是它在同一台监视器上等待。