java重排序发生在不破坏happens-before关系的前提下,由编译器、jit或cpu为优化性能而调整指令顺序;常见于多线程共享变量读写、对象未安全发布等场景。

Java重排序到底在什么情况下发生?
JVM和CPU都可能对指令重排序,但不是“想怎么排就怎么排”。关键约束来自 happens-before 规则——它定义了哪些操作必须按源码顺序执行,哪些可以重排。只要不破坏 happens-before 关系,编译器、JIT、CPU 都可自由优化。
常见错误现象:
- 多线程下,一个线程写完
flag = true和data = 42,另一个线程看到flag == true却读到data == 0 - 对象构造未完成就被其他线程引用(如单例双重检查锁中未加
volatile)
使用场景:
- 所有涉及共享变量读写的多线程代码
-
synchronized块、volatile字段、Thread.start()/join()等隐式建立happens-before的地方
注意:
立即学习“Java免费学习笔记(深入)”;
-
happens-before不是内存屏障的同义词,它是语义规则;内存屏障是实现该规则的底层手段 - 即使没有竞态,重排序也可能暴露未初始化字段(如对象逃逸时)
volatile字段为什么能禁止重排序?
volatile 写操作会在其前后插入内存屏障:写前加 StoreStore,写后加 StoreLoad;读操作则加 LoadLoad 和 LoadStore。这直接限制了编译器和CPU的重排自由度。
参数差异:
-
volatile只保证单个变量的可见性和禁止特定方向的重排序,不保证原子性(如i++仍非线程安全) - 它不能用于数组元素(需用
AtomicIntegerArray等替代)
性能影响:
-
volatile读几乎无开销(x86 下常被优化为普通读) -
volatile写在 x86 上等价于mov + mfence,比synchronized轻量,但比普通写重得多
示例:
class LazyInit {
private volatile static Helper helper;
static Helper getInstance() {
if (helper == null) {
synchronized(LazyInit.class) {
if (helper == null) {
helper = new Helper(); // 构造过程不会被重排到 volatile 写之后
}
}
}
return helper;
}
}
哪些操作天然满足happens-before?
JDK 明确定义了 8 条 happens-before 规则,实际编码中最常踩坑的是忽略其中几条:
-
Thread.start()happens-before 该线程的任意动作 - 该线程所有动作 happens-before
join()返回 - 对同一个
volatile变量的写 happens-before 后续对该变量的读 - 锁的解锁 happens-before 后续对同一锁的加锁
容易被忽略的点:
-
System.out.println()没有happens-before语义,不能靠它“刷缓存” - 对象构造方法结束,并不自动对其他线程建立
happens-before(除非通过安全发布,如volatile、final字段、锁、静态初始化器) -
final字段的语义仅在构造完成且对象未逸出时生效;若构造中this引用逃逸,final也不保序
手动插入内存屏障要小心什么?
JDK 9+ 提供了 VarHandle 的 fullFence()、acquireFence()、releaseFence(),但极少需要手写。滥用反而破坏可读性和可维护性。
常见错误现象:
- 在
synchronized块里再加fullFence()—— 多余,且可能干扰 JIT 优化 - 用
Unsafe.getUnsafe().storeFence()(已强烈不建议)绕过volatile语义,结果在不同 CPU 架构上行为不一致
使用条件:
- 仅在极少数 JNI 或高性能并发库(如
ConcurrentLinkedQueue)内部才需精确控制屏障类型 - 必须配合
@Contended、缓存行对齐等手段才能真正发挥效果,否则可能因伪共享抵消收益
真正该做的:
- 优先用
volatile、final、synchronized表达语义 - 把屏障当“实现细节”,而不是“同步手段”
- 测试必须覆盖 ARM/AArch64(重排序更激进),不能只跑 x86
复杂点在于:重排序不是 bug,而是正确并发编程的前提假设。一旦开始怀疑重排序,说明你已经站在了内存模型的深水区——这时候最危险的不是不懂屏障,而是以为加了 volatile 就万事大吉。










