假设我知道我将在x64 cpu上运行,我可以忽略哪些JVM同步实践?

我知道JVM内存模型是为CPU的最小公分母而设计的,因此它必须假设JVM可以运行的最弱的cpu模型(例如ARM)。

现在,考虑到x64具有相当强大的内存模型,假设我知道我的程序只能在64位x86 CPU上运行,我可以忽略哪些同步实践? 当我的程序通过虚拟化运行时,这也适用吗?

例:
众所周知,JVM的内存模型需要同步对long和double的读/写访问,但可以假设其他32位原语(如int,float等)的读/写是primefaces的。

但是,如果我知道我在64位x86机器上运行,我是否可以忽略使用long / double上的锁定知道cpu将自动读取/写入64位值并保持它们不稳定(就像我对int / floats一样) )?

我知道JVM内存模型是为CPU的最小公分母而设计的,因此它必须假设JVM可以运行的最弱的cpu模型(例如ARM)。

那不对。 JMM源于各种竞争力量之间的妥协:对较弱内存模型的渴望,以便程序可以在具有弱内存模型的硬件上更快; 希望允许某些优化的编译器编写者的愿望; 并希望并行Java程序的结果是正确和可预测的,并且如果可能的话(!)可以被Java程序员理解。 有关内存模型问题的一般概述,请参阅Sarita Adve的CACM文章 。

考虑到x64具有相当强大的内存模型,假设我知道我的程序只能在[x64] CPU上运行,我可以忽略哪些同步实践?

没有。 问题是内存模型不仅适用于底层硬件,还适用于执行程序的JVM,实际上也适用于JVM的JIT编译器。 编译器可能决定应用内存模型中允许的某些优化,但如果您的程序基于底层硬件对内存行为做出无根据的假设,那么您的程序将会中断。

您询问了x64和primefaces64位写入。 可能在x64机器上不会发生任何单词撕裂。 我怀疑任何JIT编译器都会将64位值作为优化分解为32位写入,但您永远不会知道。 但是,您似乎不太可能使用此function来避免程序中的同步或易失性字段。 如果没有这些,对这些变量的写入可能永远不会对其他线程可见,或者它们可能随意地针对其他写入进行重新排序,可能会导致程序中的错误。

我的建议是首先正确应用同步以使程序正确。 你可能会感到惊喜。 同步操作已经过大量优化,在常见情况下可以非常快。 如果您发现存在瓶颈,请考虑使用锁定拆分,使用挥发性或转换为非阻塞算法等优化。

UPDATE

OP已经更新了问题,使用volatile而不是锁和同步更具体一些。

事实certificate, volatile不仅具有内存可见性语义。 它还使得longdouble访问primefaces,而这些类型的非易失volatile变量不是这种情况。 参见JLS第17.7节 。 您应该能够依赖volatile来在任何硬件上提供primefaces性,而不仅仅是x64。

虽然我在这里,有关Java内存模型的更多信息,请参阅Aleksey Shipilev的JMM Pragmatics谈话记录 。 (Aleksey也是JMH的家伙。)这次演讲中有很多细节,还有一些有趣的练习来测试一个人的理解。 这个话题的一个总体结论是,依靠一个人关于内存模型如何工作的直觉往往是错误的,例如在缓存行或写缓冲区方面。 JMM是关于内存操作和各种约束( 同步发生在之前等)的forms主义 ,它们决定了这些操作的顺序。 这可能会产生非常违反直觉的结果。 试图通过考虑特定的硬件属性来超越JMM是不明智的。 它会回来咬你。

你仍然需要处理线程安全性,所以波动性语义和内存栅栏仍然很重要

我的意思是,例如在Oracle Java中,大多数低级别同步操作最终都在Unsafe(docjar.com/docs/api/sun/misc/Unsafe.html#getUnsafe)中,而后者又有很长的本机列表方法。 因此,最终,这些同步实践和许多其他低级操作都由它们所属的JVM封装。 x64与x86的jvm不同。

在再次阅读您编辑的问题之后:加载/存储操作的primefaces性是一个主题。 所以不,你不必担心x64上的primefaces64位加载/存储。 但由于这不是所有同步问题的结束,请参阅其他答案。

始终包含JVM内存模型声明需要它们的内存屏障,然后让JVM在可以用于不同平台时对其进行优化。

知道你只在x86 CPU上运行并不意味着你可以放弃使用内存屏障。 除非您知道您将只运行单核x86 cpus;)在今天的多核心世界中,没有人真正知道。

为什么? 因为java内存模型有两个主要问题。

  1. 核心与核心之间数据的可见性
  2. 发生在担保之前,又称重新订购。

如果没有内存屏障,其他内核可见的操作顺序可能会变得非常混乱; 即使是x86提供的更强保证也是如此。 x86只有在数据进入cpu缓存后才能确保一致性,并且虽然它的排序保证非常强大,但只有在Hotspot告诉CPU写出缓存时才会启动它们。

如果没有volatile / synchronized,则编译器(javac和hotspot)将决定何时执行这些写操作以及按什么顺序执行。 他们决定在寄存器中长时间保存数据是完全有效的。 一旦交叉了易失性或同步的内存屏障,JVM就会知道告诉CPU将数据发送到缓存。

正如Doug Lea在JSR-133 Cookbook中记录的那样,大多数x86障碍都被简化为无操作指令,以保证订购。 因此,JVM将使我们的指令尽可能高效。 代码到Java内存模型,让Hotspot发挥其神奇作用。 如果Hotspot可以certificate不需要synchronized,则可以完全删除它。

最后,双重检查锁定模式也被certificate在多核x86上被打破了; 尽管有更强的记忆保证。 Bartos Milewski在他的C ++ 博客上写了一些很好的细节,这次是针对Java的

编译器写入已经处理了您想要做的事情。 许多易失性读/写障碍最终将在x64上无操作。 也可以认为由于编译器优化也可能引起重新排序,并且可能不依赖于硬件。 对于例外的良性数据竞争 – 例如String hashCode。 请参阅: http : //jeremymanson.blogspot.com/2008/12/benign-data-races-in-java.html

另请参阅页面,了解x64上的操作说明。 请参阅: http : //gee.cs.oswego.edu/dl/jmm/cookbook.html请参阅多处理器部分。

我建议不要对硬件进行任何特定的优化。 您最终可能会编写不可维护的代码。 编译器编写器已经提供了足够的HardWork

它不仅取决于CPU,还取决于JVM,操作系统等。

有一件事你可能会确定:如果涉及线程同步,不要假设任何事情。