volatile主要保证可见性和禁止指令重排序,但不保证原子性;适用于状态标志、单例发布等轻量场景,复合操作如count++仍需synchronized或AtomicInteger。

volatile 主要通过保证可见性和禁止指令重排序来解决多线程共享状态的同步问题,但它不提供原子性保障。它适合用于“状态标志”这类简单、独立的读写场景。
可见性:让修改对其他线程立即可见
普通变量在多线程中可能被缓存在线程私有的工作内存(如 CPU 缓存)里。一个线程改了值,另一个线程可能一直读到旧副本,导致逻辑卡死或行为异常。
volatile 强制:
- 每次写操作后,立即将最新值刷新到主内存;
- 每次读操作前,强制丢弃本地缓存,直接从主内存加载最新值。
这样,只要一个线程把 volatile 变量设为 true,其他线程下一次读就能看到这个变化——比如用作运行开关:volatile boolean isRunning = true;,调用 stop() 改为 false 后,工作线程能及时退出循环。
立即学习“Java免费学习笔记(深入)”;
禁止指令重排序:确保关键操作顺序不被破坏
编译器和 CPU 为优化性能,可能调整语句执行顺序。这对单线程无影响,但在多线程下可能引发严重问题。
典型例子是双重检查锁单例:
- 构造对象实际包含三步:分配内存 → 初始化对象 → 将引用赋给静态变量;
- 若无 volatile,JVM 可能将“赋引用”提前到“初始化完成前”,导致其他线程拿到一个未初始化完毕的对象;
- 加上 volatile 后,JVM 插入内存屏障,禁止该重排序,确保对象完全构造好后才对外可见。
它不解决什么?—— 原子性缺失是关键限制
volatile 不能保证复合操作的原子性。例如:
-
count++实际是“读取→加1→写回”三步,即使count是 volatile,多个线程仍可能同时读到相同旧值,各自加1后写回,造成结果丢失; - 类似地,
if (flag) doSomething();中的判断与后续动作也不构成原子操作。
这类场景必须配合 synchronized、Lock 或 AtomicInteger 等真正支持原子操作的机制。
适用场景总结
volatile 最适合以下几类轻量级状态共享:
- 布尔型状态标志(如
isShutdown、isPaused); - 一次性安全发布(如单例实例引用);
- 作为触发信号,配合其他同步手段使用(如与 wait/notify 或 LockSupport 配合)。
它不是万能锁,而是精准作用于“谁改了、谁立刻知道”和“按我写的顺序执行”这两个关键环节。用对地方,简洁高效;误当锁用,隐患难查。


















