volatile解决多线程内存可见性问题,不保证原子性,也不能替代锁;它强制读写主内存并禁止指令重排序,适用于状态标志等简单场景。

volatile 解决的是多线程环境下变量的内存可见性问题,不保证原子性,也不能替代锁。
为什么需要 volatile:主内存与工作内存的不一致
Java 内存模型(JMM)规定,每个线程都有自己的工作内存(如 CPU 寄存器、高速缓存),线程对变量的操作都在工作内存中进行。当线程修改一个变量时,可能只更新了本地副本,未及时写回主内存;其他线程读取时,仍从自己缓存中取旧值——这就导致“一个线程改了,另一个线程看不见”。volatile 强制每次读都从主内存加载,每次写都立即刷回主内存,从而让修改对其他线程“立即可见”。
volatile 能做什么:可见性 + 禁止指令重排序
它提供两项保障:
- 可见性保障:写 volatile 变量后,该线程之前的所有操作结果对其他线程可见(happens-before 关系)
- 禁止重排序:编译器和处理器不会将 volatile 读/写与前后的普通读写重排序(但 volatile 读与 volatile 写之间仍可重排)
例如单例模式中的双重检查锁定(DCL),若 instance 不加 volatile,可能导致其他线程看到未初始化完成的对象(因对象构造被重排序)。
立即学习“Java免费学习笔记(深入)”;
volatile 不能做什么:不解决原子性问题
对 volatile 变量的复合操作(如 i++)依然不是原子的,因为包含“读-改-写”三步。即使变量声明为 volatile,多个线程同时执行 i++ 仍可能丢失更新。
- 错误用法:volatile int count = 0; → count++ 无法保证线程安全
- 正确替代:用 AtomicInteger.incrementAndGet(),或 synchronized 控制临界区
适用场景:状态标志、简单通知、轻量级同步
典型用途包括:
- 线程间的状态通知,如 volatile boolean running = true;,用于控制循环退出
- 一次性安全发布(如 DCL 单例中的 instance 字段)
- 作为信号量,配合其他同步机制使用(如 wait/notify 场景中做条件检查)
注意:仅当变量本身无依赖关系、不参与复合运算时,volatile 才能独立保证正确性。










