volatile修饰共享变量可破除死循环,因其强制每次读取都从主内存获取最新值、每次写入立即刷回主内存,并插入内存屏障禁止重排序;而普通变量因编译器/jit优化可能缓存旧值导致线程永远读不到更新。

用 volatile 修饰共享状态变量,就能让线程及时看到值的变化,从而跳出死循环。
为什么普通变量会导致死循环
线程在执行 while(!flag) 这类循环时,JIT 编译器可能把 flag 当作“不会变的常量”来优化,直接从寄存器或 CPU 缓存读取旧值;即使另一个线程改了主内存中的 flag,当前线程也一直不重新加载——结果就是永远卡在循环里。
volatile 怎么打破这个僵局
它强制每次读都从主内存取最新值,每次写都立刻刷回主内存,并插入内存屏障防止重排序。这样,只要 flag = true 执行完成,其他线程下一次读 flag 就一定能拿到 true。
- 声明时加上 volatile:private static volatile boolean flag = false;
- 不需要改逻辑、不用加锁、也不影响性能(读几乎无开销)
- 适用于纯状态通知场景,比如开关、完成标记、中断信号
哪些情况 volatile 不够用
如果操作不是简单的“赋值”,而是依赖当前值的复合动作,volatile 就无法保证正确性:
- count++:涉及读-改-写三步,即便 count 是 volatile,仍可能丢失更新
- 多个变量有先后依赖:比如先设 data = 42,再设 ready = true;volatile 不能保证其他线程看到这两个写操作的顺序
- 需要等待或条件判断(如 wait/notify):必须配合 synchronized 或 Lock
替代方案对比
除了 volatile,还有几种方式也能让变量修改对其他线程可见:
- synchronized 块:进入时读主内存,退出时刷回主内存,天然带可见性保障,但有锁开销
- Thread.sleep(0) 或 System.out.println():能间接触发内存同步(因底层调用了安全点或 I/O 屏障),但属于“黑魔法”,不推荐用于生产
- AtomicBoolean 等原子类:内部用 volatile + CAS 实现,比单纯 volatile 更强,适合需要 read-modify-write 的场景
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











