gpt4 book ai didi

java - volatile 写入的成本

转载 作者:行者123 更新时间:2023-12-03 12:59:31 25 4
gpt4 key购买 nike

我已经研究了x86硬件中Java volatile 写入的成本。
我打算在共享内存位置上使用Unsafe的putLongVolatile方法。查看实现,将putLongVolatile get转换为Link中的Unsafe_SetLongVolatile,然后转换为AtomicWrite,再转换为围栏Link

简而言之,每个 volatile 写入都将转换为原子写入,然后再转换为全围栏(x86中的mfence或锁定的add指令)。

问题:

1)为什么x86需要fence()?由于商店-商店的排序,简单的编译器障碍还不够吗?完整的栅栏似乎非常昂贵。

2)是不安全的putLong而不是putLongVolatile更好的选择吗?在多线程情况下会很好吗?

最佳答案

问题1的答案:

没有完整的屏障,您将无法获得JMM所需的顺序一致性。

因此X86提供了TSO。因此,您可以免费获得以下障碍[LoadLoad] [LoadStore] [StoreStore]。唯一缺少的是[StoreLoad]。

负载具有语义

r1=X
[LoadLoad]
[LoadStore]

商店具有发布语义
[LoadStore]
[StoreStore]
Y=r2

如果要先存储然后进行加载,则最终会得到以下结果:
[LoadStore]
[StoreStore]
Y=r2
r1=X
[LoadLoad]
[LoadStore]

问题是加载和存储仍然可以重新排序,因此顺序不一致。这对于Java内存模型是必需的。防止这种情况的唯一方法是使用[StoreLoad]。并且最合乎逻辑的地方是将其添加到写入中,因为通常读取比写入更频繁。

这可以通过 MFENCElock addl %(RSP),0完成

问题2的答案:

putLong的问题在于,不仅CPU可以对指令进行重新排序,而且编译器还可以以导致指令重新排序的方式更改代码。

示例:如果要在循环中执行putLong,则编译器可以决定将写操作从循环中拉出,并且该值将对其他线程不可见。如果您希望具有低开销的单一编写器性能计数器,则可能需要看看putLongRelease/putLongOrdered(oldname)。这将阻止编译器执行上述操作。您可以免费获得X86上的发行语义。

但是很难给出一个完全适合您第二个问题的解决方案,因为这取决于您的目标是什么。

关于java - volatile 写入的成本,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43460725/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com