volatile不能保证复合操作原子性,仅确保单次读/写操作的可见性(强制主内存读写)和有序性(禁止指令重排),故适用于状态标志等简单场景,不适用于i++等需“读—改—写”三步的复合操作。

volatile 在多线程状态标志切换中,不保证原子性,但能确保变量的**可见性**和**禁止指令重排序**,从而让状态变更对其他线程“即时可见”——这里的“即时”指**不被线程本地缓存延迟,也不因编译器/JIT 优化而掩盖最新值**。
为什么普通布尔变量在状态标志中会失效?
Java 线程可能把 boolean 类型的状态变量(如 running = true)缓存在 CPU 寄存器或本地内存中。即使主线程已将 running 设为 false,工作线程仍可能一直读取旧值,导致 while 循环无法退出。
这是因为: - 没有同步机制时,JVM 不保证一个线程对变量的写操作会立即刷新到主内存; - 其他线程也不保证从主内存重新读取该变量。
volatile 如何解决可见性问题?
声明为 volatile boolean running 后:
- 每次读取 running 都强制从主内存加载最新值(不走线程本地缓存);
- 每次写入 running 都强制写回主内存,并使其他 CPU 缓存中该变量的副本失效;
- 编译器和处理器不会对该变量的读写进行重排序(例如:不会把循环体内的代码提到 volatile 读之前)。
这使得“设置标志 → 工作线程检测到并退出”的逻辑链可靠成立。
立即学习“Java免费学习笔记(深入)”;
典型用法与注意事项
常见模式是配合 while 循环做协作式中断:
volatile boolean running = true;
<p>// 工作线程
new Thread(() -> {
while (running) {
// 执行任务...
doWork();
}
System.out.println("已停止");
}).start();</p><p>// 主线程稍后触发停止
Thread.sleep(1000);
running = false; // 其他线程立刻能看到这个变化
注意:
- volatile 不能替代 synchronized 或 Lock 处理复合操作(比如 count++);
- 若状态切换依赖多个变量协同(如 state 和 reason),volatile 单独无法保证它们的一致性,需用锁或 AtomicReference
底层保障: happens-before 规则
JMM(Java 内存模型)规定:对 volatile 变量的写操作 happens-before 后续任意线程对该变量的读操作。这是 volatile “即时生效”的理论基础。它建立了跨线程的操作顺序约束,让结果可预测、可推理。


















