重排序与内存屏障详解
请解释编译器重排序、处理器重排序和内存屏障(Memory Barrier)的关系,以及Java中如何防止重排序。
回答
屠龙少年
重排序类型:
- 编译器重排序:JIT编译器在不改变单线程语义的前提下调整指令顺序。
- 处理器重排序:CPU乱序执行(Store-Load重排序最常见)。
- 内存系统重排序: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对象时的指令重排序(分配内存→置零→构造函数→赋值引用)。