我知道JVM内存模型是为CPU的最低公分母而制作的,因此它必须假设JVM可以运行的CPU的最弱模型(例如ARM)。
这是不正确的。JMM源于各种竞争力量之间的妥协:对较弱内存模型的渴望,以便程序可以在具有弱内存模型的硬件上更快地运行;希望允许某些优化的编译器编写者的愿望;并希望并行Java程序的结果正确且可预测,并且如果可能的话(!)对于Java程序员来说是可以理解的。请参阅Sarita Adve的CACM文章,了解内存模型问题的一般概述。
考虑到 x64 具有相当强的内存模型,假设我知道我的程序只能在 [x64] CPU 上运行,我可以忽略哪些同步做法?
没有。问题在于,内存模型不仅适用于底层硬件,还适用于执行程序的 JVM,并且在实践中主要适用于 JVM 的 JIT 编译器。编译器可能会决定应用内存模型中允许的某些优化,但是如果您的程序基于底层硬件对内存行为做出不必要的假设,则程序将中断。
您询问了有关 x64 和原子 64 位写入的问题。可能是x64机器上不会发生任何单词撕裂。我怀疑任何JIT编译器都会将64位值分解为32位写入作为优化,但你永远不会知道。但是,似乎不太可能使用此功能来避免程序中的同步或易失性字段。如果没有这些,对这些变量的写入可能永远不会对其他线程可见,或者它们可以相对于其他写入任意重新排序,从而导致程序中的错误。
我的建议是首先正确应用同步以使程序正确。你可能会感到惊喜。同步操作已经过高度优化,在常见情况下可以非常快。如果发现存在瓶颈,请考虑使用锁拆分、使用易失性或转换为非阻塞算法等优化。
更新
OP 更新了问题,使其更具体地说明了如何使用而不是锁和同步。volatile
事实证明,不仅具有内存可见性语义。它还使和访问原子,对于这些类型的非变量来说,情况并非如此。请参阅 JLS 第 17.7 节。您应该能够依靠在任何硬件上提供原子性,而不仅仅是x64。volatile
long
double
volatile
volatile
虽然我在这里,但有关Java内存模型的更多信息,请参阅Aleksey Shipilev的JMM Pragmatics talk transcript。(阿列克谢也是JMH的人。这个演讲中有很多细节,还有一些有趣的练习来测试一个人的理解。演讲的一个总体结论是,依靠一个人对内存模型如何工作的直觉通常是一个错误,例如在缓存行或写入缓冲区方面。JMM 是关于内存操作和各种约束(与、之前发生等)的形式主义,用于确定这些操作的顺序。这可能会产生非常违反直觉的结果。试图通过考虑特定的硬件属性来超越JMM是不明智的。它会回来咬你。