jmm是语义规范,jvm通过orderaccess类将抽象屏障映射为硬件指令:x86下storestore→sfence、loadload→lfence、storeload→mfence,arm64则用dmb ish等实现。

Java 内存模型(JMM)本身不直接操作硬件,它是一套语义规范,用来定义多线程下共享变量的读写行为该“看起来怎样”。真正落地这些语义的,是 JVM 在编译或运行时,把 JMM 的抽象约束翻译成对应 CPU 架构能识别的内存屏障指令——这才是硬件层面的底层实现。
JMM 怎么“映射”到硬件内存屏障
JMM 规定了什么不能重排序、什么必须可见,但不指定怎么实现。JVM(如 HotSpot)通过 OrderAccess 类等机制,在关键位置插入四类抽象屏障(LoadLoad / StoreStore / LoadStore / StoreLoad),再由 JIT 编译器根据目标 CPU 架构,生成具体指令:
-
x86/x64 平台
-
StoreStore→sfence(写屏障) -
LoadLoad→lfence(读屏障) -
StoreLoad→mfence(全屏障,最重,需同步 store buffer + invalidation queue)
-
-
ARM64 平台
- 统一用
dmb ish(data memory barrier, inner shareable domain)覆盖多数场景 -
dmb ishld用于更严格的加载-数据依赖控制
- 统一用
这些指令不是“暂停 CPU”,而是向微架构发出信号:比如 mfence 会强制刷空 store buffer,并等待其他核的缓存失效请求(invalidation queue)处理完毕,确保写对所有核可见。
硬件优化带来的“伪重排”,屏障正是为它而设
现代 CPU 为提速,默认允许四类访存重排(Load-Load、Load-Store、Store-Load、Store-Store),单线程下合法(as-if-serial),但多线程中会破坏预期。背后是几个关键硬件组件在起作用:
- Store Buffer:CPU 写内存时不等 cache 写入完成,先把数据暂存于此 → 导致写“延迟可见”
- Invalidation Queue:收到其他核发来的缓存失效通知后,不立即处理,先排队 → 导致本地缓存“迟迟不更新”
- Write Combining Buffer:合并多次小写,提升带宽 → 进一步模糊写顺序
- 超标量调度器:动态选无依赖指令发射 → 实际执行顺序与代码顺序不同
这些机制共同造成“从全局视角看像重排序,实则是状态未同步”。内存屏障的作用,就是在这个链条的关键节点上“卡住”,等状态对齐后再继续。
Java Maven 项目审查工作流的通用输入处理。当 Java Maven 项目以 ZIP压缩包或 GitLab 仓库 URL 形式提供且需要...时使用。
volatile 和 synchronized 是怎么靠屏障工作的
它们不是魔法,而是 JVM 主动插入屏障的典型模式:
-
volatile 写(如
flag = true)- 后插
StoreStore + StoreLoad - 效果:确保前面所有写已落主存(刷 store buffer),且后续读不会越过本次写(等失效队列清空)
- 后插
-
volatile 读(如
if (flag))- 前插
LoadLoad + LoadStore - 效果:确保本次读取最新值(不走过期缓存),且后续写不能提前到该读之前
- 前插
-
synchronized 进入
- 插
LoadLoad + LoadStore→ 防止读到锁保护外的旧值
- 插
-
synchronized 退出
- 插
StoreStore + StoreLoad→ 确保临界区内的修改对其他线程可见
- 插
这些屏障组合,配合 MESI 等缓存一致性协议,最终让 volatile 和锁在绝大多数场景下既高效又正确。
小结:理解的关键不在“禁止乱序”,而在“控制同步点”
JMM 不对抗硬件优化,而是承认它、利用它,并在程序员关心的语义边界上,用最小代价触发硬件同步。所谓底层实现,就是 JVM 把高级语义(如 happens-before)精准翻译成对 store buffer、invalidation queue、cache line 状态的干预指令。你看不到寄存器变化,但每次 volatile 读写或锁进出,背后都有几条汇编在和 CPU 微架构对话。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










