volatile能验证多线程内存可见性:加volatile后子线程可立即读到主线程修改的值,否则可能长期读取本地缓存旧值;通过死循环检测flag变化并控制执行时序对比输出即可直观验证。

Java 中 volatile 能验证多线程修改带来的内存可见性问题,核心在于:**一个线程修改 volatile 变量后,另一个线程能立即读到新值;而普通变量则可能长期读到旧值(来自本地缓存)**。验证的关键不是“看到修改”,而是“对比有无 volatile 时的行为差异”。
用死循环检测 flag 变化来直观验证
这是最常用、效果最明显的验证方式。主线程修改标志位,子线程持续轮询,观察是否退出循环:
- 不加 volatile:子线程大概率陷入无限循环,即使主线程已把 flag 设为 true,它仍读取自己缓存中的 false
- 加上 volatile:子线程在几毫秒内就能读到 true 并退出,说明修改已刷新到主内存,且读操作强制从主内存加载
控制变量 + 精确延时,排除干扰
避免因线程调度随机性导致误判,需人为控制执行时序:
- 让子线程先启动并进入 while(flag == false) 循环
- 主线程 sleep(100) 确保子线程已稳定运行在循环中
- 再执行 flag = true(或 false),随后打印确认
- 观察子线程是否在合理时间内(如 1–10ms)打印退出日志
对比输出结果,确认可见性生效
运行两次程序,仅切换 volatile 修饰,其余代码完全一致:
- 无 volatile 版本输出示例:
子线程启动,开始检测 flag
设置 flag 为 true
(之后无任何输出,程序卡住) - 有 volatile 版本输出示例:
子线程启动,开始检测 flag
设置 flag 为 true
子线程检测到 flag = true,准备退出
注意:不能靠 System.out.println 验证“原子性”
volatile 本身不保证复合操作的原子性。例如以下代码不能验证可见性,反而会掩盖问题:
错误示范(不要这么做):
while (i++ 这里 i++ 包含读-改-写三步,volatile 只保证每次读/写可见,不保证整个自增不被其他线程穿插 —— 这是原子性问题,不是可见性问题。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











