CodeWalk

重排序与内存屏障详解

作者:屠龙少年 · 2026-05-30 12:55

请解释编译器重排序、处理器重排序和内存屏障(Memory Barrier)的关系,以及Java中如何防止重排序。

回答

屠龙少年

重排序类型

  1. 编译器重排序:JIT编译器在不改变单线程语义的前提下调整指令顺序。
  2. 处理器重排序:CPU乱序执行(Store-Load重排序最常见)。
  3. 内存系统重排序:Store Buffer/Invalidate Queue导致的可见性问题。

内存屏障(Memory Barrier): CPU指令,阻止特定类型的重排序。 | 屏障类型 | 作用 | |---------|------| | LoadLoad | 保证Load1完成后Load2才执行 | | StoreStore | 保证Store1完成后Store2才执行 | | LoadStore | 保证Load完成后Store才执行 | | StoreLoad | 保证Store1完成后Load2才执行(开销最大)|

Java中的实现

  • volatile:volatile写=StoreStore+StoreLoad;volatile读=LoadLoad+LoadStore。
  • synchronized:monitorenter/monitorexit隐式插入屏障。
  • final:final字段写入后在构造返回前插入StoreStore屏障。
  • Unsafe.loadFence/storeFence/fullFence:显式插入屏障。

as-if-serial:单线程不改变结果的前提下允许重排序。

DCL单例需要volatile的原因:防止new对象时的指令重排序(分配内存→置零→构造函数→赋值引用)。