JMM是抽象规范,通过volatile、synchronized等关键字适配不同硬件内存模型;在ARM弱模型下需插入更多内存屏障(如dmb ishst)以保障可见性与有序性,导致开销高于x86强模型。

Java 内存模型(JMM)本身是抽象规范,不直接暴露硬件差异;但它通过 volatile、synchronized 和 final 等语义,在底层依赖硬件内存模型来实现跨平台一致性。多核 ARM 架构下弱内存模型的特性,会直接影响 JMM 的实际行为表现——尤其在重排序层面,与 x86 的强内存模型形成鲜明对比。
ARM 弱模型导致更宽松的编译器+硬件重排
ARM 不保证 store-store、load-load、load-store 之间的顺序,即使代码写成:
flag = false; data = 42; flag = true;
在 x86 上,由于硬件禁止 store-store 重排,其他线程几乎不可能看到 flag == true && data == 0;但在 ARM 上,flag = true 可能先刷到内存,而 data = 42 还卡在写缓冲区或乱序执行队列中,导致其他线程“提前”读到 flag 却读不到 data。
此时仅靠 Java 源码顺序无法约束,必须借助 JMM 机制:
立即学习“Java免费学习笔记(深入)”;
- 把
flag声明为volatile→ 触发编译器插入内存屏障,并在 ARM 上生成dmb ishst(store barrier),阻止后续 store 被提前 - 用
synchronized包裹两行赋值 → 在 ARM 上会生成完整的 acquire-release 同步开销,包括 barrier 和 cache line invalidation
JMM 的 volatile 在 ARM 和 x86 上生成的指令不同
volatile 字段读写在 JMM 中定义了 happens-before 关系,但具体实现由 JVM 根据 CPU 架构适配:
- x86:
volatile write通常只加一个lock xchg或mfence(极少数场景),因硬件已提供强顺序保障 - ARM64:HotSpot JVM 对
volatile write会生成str+dmb ishst,对volatile read生成ldr+dmb ishld,确保跨核可见性
这意味着相同 Java 代码,在 ARM 上的 volatile 开销显著高于 x86 —— 不是 JVM “慢”,而是硬件要求它必须补足同步语义。
看似安全的 final 字段,在 ARM 多核下仍需警惕构造过程重排
JMM 规定:正确构造的 final 字段,在对象发布后对其他线程可见。但这依赖于“正确构造”——即构造函数内不泄露 this 引用。
在 ARM 上,即使满足该条件,若对象发布未配合同步(如无 volatile 引用、无 synchronized 发布),仍可能因写缓冲区延迟和 store-load 重排,导致其他线程看到部分初始化的对象(final 字段值未完全刷出)。x86 因硬件隐式保证更强,这类问题极少复现。
典型修复方式:
- 用
volatile引用发布对象(如volatile Holder holder = new Holder()) - 用
AtomicReference的lazySet或set(后者等价于 volatile write) - 避免无同步的对象逃逸,尤其在高并发初始化场景
工具链层面的可观测差异
你可以在运行时验证这些影响:
- 用
java -XX:+PrintAssembly(需 hsdis)查看 JIT 编译后 ARM64 vs x86_64 的汇编,会发现 ARM 版本频繁出现dmb ish类指令,x86 则多为mov+ 少量lock/mfence - 使用 JMH 编写微基准测试(如 volatile 写吞吐、锁竞争延迟),在 Apple M1/M2(ARM64)与 Intel Xeon(x86_64)上对比,常可见 ARM 上 volatile 开销高 2–5 倍
- OpenJDK 的
Unsafe类中putOrdered(对应memory_order_relaxed)在 ARM 上仍可能插入dmb ishst,而 x86 几乎就是裸str—— 这正体现了 JMM 对硬件弱模型的主动兜底


















