尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Java中的内存屏障(LoadLoad/StoreStore)是什么

Java中的内存屏障(LoadLoad/StoreStore)是什么 Java不提供LoadLoad/StoreStore关键字JVM是基于synchronized的、volatile或Unsafe.loadFence()等语义插入汇编层的内存屏障具体依赖CPU架构。Java里没有LoadLoad或StoreStore关键字Java语言层面根本不暴露LoadLoad、StoreStore这种内存屏障指令——它们是JVM内部CPU指令的翻译结果不是你可以直接写的语法。你写的synchronized、volatile或者Unsafe.loadFence()只有JVM才能在生成的汇编中插入相应的屏障。常见的误解是认为它可以像C一样手写std::atomic_thread_fence(memory_order_acquire)但在Java中 -volatile字段读 → 一般情况下编译后带LoadLoadLoadStore(取决于平台) -volatile字段写 → 通常带StoreStoreStoreLoad-Unsafe.loadFence()→ 强制插入LoadLoadLoadStoreHotSpot 其实x86下就是mov %rax, %rax这种空操作但语义存在)为什么x86上StoreStore经常被省略x86 CPU本身有很强的内存顺序保证:写-写-写Store-Store自然有序无需额外指令。因此Hotspot在x86上编译volatile写时StoreStore屏障经常被优化只留下StoreLoad用lock addl px86 CPU本身有很强的内存顺序保证:写-写-写Store-Store自然有序无需额外指令。因此Hotspot在x86上编译codevolatile写时StoreStore屏障经常被优化只留下StoreLoad用lock addl $0,(%rsp)等模拟)。,(%rsp)等模拟)。但这并不意味着它不重要 - ARM/Arch64没有这个保证StoreStore它将被真实地编译成dmb st指令 - 假如你写JNI或使用它Unsafe做底层并发控制跨平台不能假设StoreStore“不存在” - JMM规范要求语义不依赖硬件JVM必须在弱序平台上补充可以在强序平台上省略——这是实现细节而不是行为承诺Unsafe.loadFence()和Unsafe.storeFence()怎么选这两个是Java 9最接近底层屏障的公共API但用错了会浪费精力:Unsafe.loadFence()确保在此点之前完成所有阅读然后阅读不会重新排序到它的前面 → 对应LoadLoadLoadStoreUnsafe.storeFence()确保这一点之前所有的写作都完成了然后写作不会重新排序到它的前面 → 对应StoreStoreStoreLoad别用Unsafe.fullFence()取代前两者——它增加了更多不必要的东西LoadLoad/StoreStore在x86上组合等于多一个mfence性能损失明显它们不作用于特定的变量只是插入指令栅栏为了保护某个字段仍然需要配合volatile或者CAS语义看到LoadLoad相关错误很有可能理解JMM边界错误在运行过程中你看不到它LoadLoad barrier missingJVM不会报告这个错误信息。当真正出现问题时现象通常是 - 多线程读取未初始化的对象字段(例如final字段被重新排序看到默认值。 - 在双检锁单例中构造函数已经执行但对象已经泄露到其他线程 -Contended没有生效伪共享仍然存在这个时候该检查的不是“怎么加”LoadLoad”而是 - 是否漏了volatile装饰状态标志 - 是否在synchronized本应在锁内发布的块外读取引用 - 是否误以为Thread.start()happenss自动建立-before忘记了后续的阅读操作没有同步约束 - JVM参数如-XX:UnlockDiagnosticVMOptions -XX:PrintAssembly只有看Java代码才能看到实际生成的屏障指令。
返回列表