Java中synchronized关键字的记忆效应
作者:互联网
这可能之前已经得到解答,但由于问题的复杂性,我需要确认.所以我重新提出这个问题
问题1:当线程进入同步块时,内存屏障将包括触摸的任何字段,而不仅仅是我同步的对象的字段?因此,如果在同步块内修改了许多对象,则在线程内存缓存之间会有大量内存移动.
Thread 1
object.field1 = "";
synchronized (lock) {
farAwayObject.field1 = "";
farAwayObject.evenFarther.field2 = "";
}
Thread 2. assuming thread ordering is correct
synchronized (lock) {
//thread 2 guaranteed to see all fields above as ""
//even object.field1 ?
}
问题2:是object.field1 =“”;在线程1中隐含地部分发生在之前的关系?
我希望它是,但它可能不会.如果不是,有一个技巧,使它没有把它放入同步块?否则很难在程序上推理
将所有内容放在synchronized {}之下是不切实际的.
编辑:澄清:object.field1不易变,问题是“将线程2保证看到线程1的写入,至少”.我的问题是内存可见性.为了论证,让我们说只有线程1写入非易失性object.field1.
问题2可以改写为
“锁定推送上的同步块是否会在同一个锁上同步的其他线程看到之前发生变化?”
解决方法:
When a thread enters a synchronized block, the memory barrier will
include any fields touched, not just fields of the object that I
synchronized on
假设farAwayObject和evenFarther的字段总是通过在应用程序周围获取对同一对象的锁定来修改和接受,所有线程将始终看到对farAwayObject和甚至更远的更新,因为synchronized强制执行before-before条件.
//thread 2 guaranteed to see all fields above as ""
对于object.field1,如果不知道如何声明它,则不能这样说.假设field1是一个未标记为volatile的引用,它将不会成为关系之前发生的一部分,并且线程可能会看到它的陈旧值.
I hope it is but It might not. If not is there a trick to make it so
without putting it into the sync block?
是.将object.field1标记为volatile.
添加您的编辑:
The question 2 can be rephrased as
“Will a synchronized block on a lock push changes made before to be
seen by other threads synchronizing on the same lock? “
AFAIK答案是肯定的,前提是写线程在读取线程之前获取锁定.不幸的是,这通常是您无法保证的,这就是为什么object.field1需要标记为volatilet语句需要在synchronized块内移动的原因.
看一下JSR 133,它讲述了当线程退出同步块时缓存被刷新到主内存.这应该进一步澄清事情.
标签:java,multithreading,java-memory-model 来源: https://codeday.me/bug/20190611/1218044.html