volatile关键字通过jmm的happens-before规则保障可见性与有序性:写操作happens-before后续读操作,jvm插入内存屏障禁止相关重排序,每次读从主内存加载、每次写立即刷新到主内存,但不保证复合操作原子性。

volatile 关键字本身不直接“禁止重排序”,而是通过建立 happens-before 关系,间接约束编译器和处理器的重排序行为,从而在多线程场景下保障内存操作的可见性与有序性。
volatile 变量规则是核心依据
Java 内存模型(JMM)明确定义了 volatile 变量规则:对一个 volatile 变量的写操作 happens-before 后续对该变量的读操作。
- 这个“后续”指时钟顺序上的后续,不要求代码紧邻,但必须是同一变量、且读发生在写之后(逻辑上或实际执行中)
- 该规则独立于线程,跨线程生效 —— 写线程的操作对读线程可见,前提是读操作确实发生在写操作之后
- 它不是靠“加锁”实现的,而是由 JVM 在 volatile 字段的读/写处插入特定内存屏障(如 StoreLoad 屏障),阻止相关指令跨越屏障重排
它如何保障可见性与有序性
volatile 的作用是组合生效的:
- 可见性:每次读 volatile 变量都从主内存重新加载;每次写都立即刷新到主内存,避免线程间使用过期缓存值
- 有序性:写 volatile 变量前的所有普通读写操作,不能被重排序到该写之后;读 volatile 变量后的所有普通读写操作,不能被重排序到该读之前
- 例如:
x = 42; flag = true;(flag 是 volatile),那么 x=42 一定在 flag=true 之前对其他线程可见 —— 因为x=42happens-beforeflag=true(程序次序规则),而flag=truehappens-before 其他线程读flag(volatile 规则),再经传递性,x=42happens-before 读 flag 的线程看到 flag==true
注意它不保证原子性
volatile 无法让复合操作变成原子操作:
-
count++即使 count 是 volatile,仍包含读-改-写三步,多个线程并发执行仍可能丢失更新 - 它只保证单个读或单个写的原子性(如
flag = true或if(flag)),不保护语义上的“操作组” - 需要原子性时,应配合 synchronized、Lock 或 AtomicInteger 等工具
与 happens-before 其他规则协同工作
volatile 规则不是孤立的,常与其他 happens-before 规则共同构成完整可见性链条:
- 程序次序规则(同一线程内,前操作 happens-before 后操作)提供基础顺序
- volatile 规则连接不同线程的读写动作
- 传递性规则将两者串联:A → B → C ⇒ A happens-before C
- 例如双重检查锁定(DCL)单例中,volatile 修饰 instance 就是为了让构造完成(写入对象引用)happens-before 后续任意线程读取 instance,防止看到未初始化的对象
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











