volatile通过happens-before规则和内存屏障禁止特定重排序来保证有序性:写操作happens-before后续读操作,写时加StoreStore+StoreLoad屏障,读时加LoadLoad+LoadStore屏障,确保双重检查单例中对象完全初始化后才被发布,但不保证复合操作原子性。

volatile 关键字配合 Java 内存模型(JMM)保证有序性,核心在于它借助 happens-before 规则 和 内存屏障(memory barrier) 禁止特定方向的指令重排序,从而确保程序执行顺序符合开发者预期。
volatile 写与读构成 happens-before 关系
JMM 明确规定:对一个 volatile 变量的写操作 happens-before 任意后续对该变量的读操作。这意味着:
- 写操作之前的所有内存操作(如普通变量赋值、对象字段初始化等),对后续读该 volatile 变量的线程来说一定是可见的;
- 读操作之后的所有内存操作,不会被重排序到该读操作之前;
- 这个语义不依赖锁或同步块,是语言级的轻量保障。
通过内存屏障阻止重排序
volatile 的有序性不是靠“禁止所有重排”,而是插入两类内存屏障来约束编译器和处理器的行为:
- 写 volatile 变量时:在写操作后插入 StoreStore 屏障 + StoreLoad 屏障,防止其后的读/写操作被重排到写 volatile 之前;
- 读 volatile 变量时:在读操作前插入 LoadLoad 屏障 + LoadStore 屏障,防止其前的读/写操作被重排到读 volatile 之后。
这些屏障限制了指令重排的自由度,使 volatile 成为构建安全无锁逻辑(如状态标志、双重检查单例)的关键基础设施。
立即学习“Java免费学习笔记(深入)”;
典型场景:双重检查锁定单例中的有序性保障
若单例实例字段未用 volatile 修饰,JVM 或 CPU 可能将对象构造完成前的写操作(如字段赋值)与引用赋值(instance = new Singleton())重排序,导致其他线程看到一个已分配但尚未初始化完毕的对象引用。加上 volatile 后:
- 构造对象的所有步骤(包括字段初始化)必须在 volatile 写之前完成;
- 后续读取该 volatile 引用的线程,一定能看到完全初始化的对象状态。
注意:有序性 ≠ 原子性
volatile 仅保证单个读或写的有序性和可见性,不保证复合操作(如 count++)的原子性。这类操作仍需 synchronized 或 AtomicInteger 等机制保护。


















