volatile保证变量可见性和禁止指令重排序,但不保证原子性;每次读写都强制主内存操作,插入内存屏障限制重排序,适用于状态标志等简单场景。

volatile 是 Java 中用于修饰变量的关键字,它的核心作用是**保证变量的可见性**,并**禁止指令重排序**,但**不保证原子性**。它不是锁,也不能替代 synchronized 或 Lock,但在特定场景下能以更轻量的方式解决部分并发问题。
volatile 如何保证可见性
在多线程环境下,每个线程可能把变量从主内存读到自己的工作内存(如 CPU 缓存)中操作。若一个线程修改了该变量,其他线程可能看不到最新值——这就是可见性问题。
volatile 修饰的变量,每次读取都强制从主内存读,每次写入都立即刷回主内存,从而让所有线程“看到同一个最新值”。
- 适用于“一个线程写、多个线程读”的简单状态标志,比如:private volatile boolean running = true;
- 不能用于需要“读-改-写”复合操作的场景(如 count++),因为 ++ 操作本身不是原子的
volatile 如何禁止指令重排序
编译器和处理器为了优化性能,可能调整语句执行顺序(只要单线程结果不变)。但这种重排序在多线程下可能引发问题。
volatile 变量的读写会插入内存屏障(Memory Barrier),限制其前后指令的重排序范围:
- 写 volatile 变量前的所有操作,不会被重排到该写之后
- 读 volatile 变量后的所有操作,不会被重排到该读之前
- 这个特性常被用于实现“双重检查锁定(DCL)”中的安全对象初始化
volatile 的能力边界:为什么它不保证原子性
可见性和有序性 ≠ 原子性。例如:
立即学习“Java免费学习笔记(深入)”;
private volatile int counter = 0;counter++;
这行代码实际包含三步:读 counter → 加 1 → 写回 counter。volatile 只能确保每一步的读/写操作对其他线程可见,但无法阻止两个线程同时读到相同旧值、各自加 1、再写回,最终只增加了一次。
- 需要原子性时,应使用 AtomicInteger、synchronized 或显式锁
- volatile 适合做状态开关、标志位、单次写入后只读的引用(如单例对象的引用)
典型使用场景举例
常见且安全的用法包括:
- 线程间通信的布尔标志:volatile boolean shutdownRequested;
- 发布不可变对象的引用(如配置对象):volatile Config currentConfig;
- 双重检查单例中的实例字段:private static volatile Singleton instance;
不推荐用于计数器、累加器、依赖多个 volatile 变量协同逻辑的场景。










