Java-volatile可见性-为什么改了标志位线程却读不到
2026/9/16 9:10:14 网站建设 项目流程

Java volatile 可见性:为什么改了标志位线程却读不到

主线程改了boolean标志,工作线程却读不到,本质是 volatile 缺失导致的可见性问题。本文讲清楚 JMM 工作内存/主内存模型、volatile 的可见性与有序性,以及它不保证原子性的边界。

一、问题案例

一个后台任务用boolean标志控制退出,主线程把标志设成false,工作线程的while循环却一直退不出来。

classWorkerimplementsRunnable{privatebooleanrunning=true;// ❌ 没加 volatilepublicvoidrun(){while(running){/* 干活 */}}publicvoidstop(){running=false;}}

二、原理详解:JMM 与可见性

Java 内存模型(JMM)里,每个线程有自己的工作内存(高速缓存),共享变量在主内存。

  • running没加 volatile → 工作线程可能把它缓存进自己的工作内存;
  • 主线程调stop()改的是主内存的值;
  • 工作线程读的是自己工作内存的旧值 → 永远看不到变化。

volatile干两件事:

  1. 保证可见性:每次读写都直连主内存,改了就立刻能被别的线程看到;
  2. 禁止指令重排:保证写读顺序,防止拿到「半初始化」的对象。

但 volatile 不保证原子性i++这种「读-改-写」复合操作,多线程下依然会丢更新。

三、实战代码

privatevolatilebooleanrunning=true;

一行搞定标志位可见性问题。

四、常见踩坑

  • i++不是原子的:要用AtomicInteger或锁。
  • 双重检查锁(DCL)单例要加 volatileinstance = new Xxx()不是原子操作,可能发生指令重排,导致别的线程拿到未初始化完的对象;instance加 volatile 可以禁止这种重排。

五、总结

  • 多线程共享的标志位,加 volatile
  • volatile 保证可见性 + 有序性,不保证原子性
  • 复合操作(i++check-then-act)交给AtomicX或锁。

我是无羡(小剑),全栈偏后端的独立开发者。

作品集:无羡 · 独立开发者作品集

如果对你有帮助,欢迎点赞、收藏、关注。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询