Java内存模型通过JVM将抽象内存屏障映射为硬件指令:x86下LoadLoad/LoadStore通常无需指令,StoreStore可能用sfence,StoreLoad必用mfence或lock空操作;ARM下各类屏障均需dmb指令。

Java 程序员通常不直接写 lfence、sfence 或 mfence,但这些指令确实在 JVM 底层真实存在,并被悄悄插入到生成的机器码中——它们是 Java 内存模型(JMM)落地为硬件行为的关键桥梁。
JVM 不暴露硬件指令,而是通过 内存屏障抽象(如 LoadLoad、StoreStore 等)来表达语义,再由 JIT 编译器根据运行时 CPU 架构,把抽象屏障映射为对应平台的实际指令。
x86 平台下 JVM 如何映射内存屏障
x86 是强内存模型,重排序限制较严,但仍需屏障控制:
-
LoadLoad和LoadStore→ 通常 不需要指令(x86 天然保证 Load 不会越过 Load 或 Store) -
StoreStore→ 编译器可能省略,但若涉及非易失性写或跨缓存行操作,JIT 可能插入sfence -
StoreLoad→ 这是最关键也最昂贵的屏障,在 x86 上 必须用mfence(或lock addl $0, (%rsp)这类带 lock 前缀的空操作)- 因为 x86 允许 Store 后面的 Load 提前执行(Store-Load 重排序),而 JMM 要求 volatile 写后读必须看到最新值,所以此处强制全屏障
举例:
volatile int flag = 1;后紧跟int x = data;,JVM 在flag = 1后插入mfence,确保data的读不会提前到flag写之前。
ARM 平台下的映射更频繁且语义不同
ARM 是弱内存模型,几乎每个屏障抽象都需显式指令:
-
LoadLoad→dmb ishld(数据内存屏障,仅约束 Load) -
StoreStore→dmb ishst(仅约束 Store) -
LoadStore/StoreLoad→dmb ish(全屏障,类似 x86 的mfence) -
dsb sy则用于更强同步(如线程退出、锁释放后刷新所有缓存)
JVM 在 ARM 上不会省略屏障,哪怕只是 volatile 读写,也会生成对应 dmb 指令 —— 因为硬件不保证顺序,必须靠指令显式约束。
分析 Java Spring Boot 后端 Controller 代码,自动生成 Markdown 格式的接口文档。当用户说“生成 Java 接口文档”、“生成 API 文档”、“从 Spring 代码生成文档”时触发。
JVM 怎么决定插哪条指令?
核心逻辑在 OrderAccess 类和平台相关汇编生成器中:
- JIT 编译时,根据当前指令序列的 JMM 抽象屏障类型 + 目标 CPU 架构 查表匹配
- 例如:
OrderAccess::storestore()在 x86_64 下可能展开为空或sfence;在 aarch64 下一定生成dmb ishst -
volatile字段访问、synchronized退出、Unsafe.storeFence()等都会触发对应屏障插入点
你可以在 -XX:+PrintAssembly 输出中看到类似:
movl $1, %eax movl %eax, 0x10(%rip) # volatile write mfence # <hr><h3>注意:lock 前缀不是屏障,但效果等价</h3><p><code>lock addl $0, (%rsp)</code> 这类指令在 x86 上常被用作 <code>StoreLoad</code> 替代方案,因为:</p>
- 它隐含全内存屏障语义(锁总线/缓存行)
- 比
mfence更轻量(尤其在老 CPU 上) - JVM 在某些场景(如
Unsafe.fullFence())会优先选lock空操作而非mfence
但它本质是原子指令,不是屏障指令 —— 只是“恰好”达成屏障效果。
不复杂但容易忽略
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










