官方说明说
和
来自here。
这是否意味着对 volatile 变量的任何写入都会使正在执行的线程将其缓存刷新到主存储器中,而从 volatile 字段中进行的每次读取都会使线程从主存储器中重新读取其变量?
我问是因为相同的文本包含了这一说法
这句话使我非常困惑。我肯定知道使用同步语句进行常规锁获取和释放不是正确的-如果某个线程释放了任何监视器,则它对所有其他线程所做的所有更改都将变为对其他所有线程可见(更新:实际上不正确-观看最佳答案)。在stackoverflow上甚至还有一个question about it。但据指出,无论出于何种原因,对于可变字段而言,情况并非如此。我无法想象在保证之前发生的任何实现,该实现不会使更改对其他线程(不读取相同的volatile变量的线程)可见。至少可以想象一个实现,它与前两个引号没有矛盾。
此外,在发布此问题之前,我进行了一些研究,例如this article,其中包含此句子
提到的指令是在写入 volatile 字段时发生的指令。
那么,该重要说明应该是什么意思?还是我想念什么?也许那条纸条是完全错误的?
回答?
经过更多研究之后,我只能在有关 volatile 字段及其对非 volatile 字段更改的影响的官方文档中找到以下声明:
来自here。
我不知道这是否足以得出结论,只有在读取相同volatile的线程中才能保证这种事前发生的关系。因此,到目前为止,我只能总结一下结果尚无定论。
但是在实践中,我建议考虑线程A
写入易失字段时所做的更改,只有在线程B
读取相同的volatile字段时,才能保证对线程B
可见。以上来自官方消息的引用强烈暗示了这一点。
最佳答案
您正在从完全错误的角度看待这个问题。首先,您引用的是JLS
,而不是谈论冲洗,这将是该规范的实现细节。您需要依靠的绝对唯一的东西就是JLS,可能还不知道其他任何东西,但是并不能证明任何形式或形式的规范是对还是错。
错误的根本原因是:
实际上,在x86
上,您可能是正确的,但是JLS
and the official oracle tutorial mandates that:
为后继的操作(如果需要,请阅读两个操作,如果您更简单)建立了Happens-before。一个线程释放该锁,另一个线程获取它-这些是后续的(release-acquire semantics
)。volatile
也会发生相同的事情-一些线程对此进行写操作,而当其他某个线程通过后续读取观察到该写操作时,则建立before-before。