P20 volatile 有哪些应用场景
面试题:volatile 是什么?有哪些使用场景?
1. volatile 是什么
volatile 是 Java 提供的轻量级同步机制,两个核心语义:
- 可见性:一个线程修改 volatile 变量后,其他线程立即可见(写后强制刷新主内存,读前强制从主内存读取);
- 禁止指令重排序:volatile 读写会插入内存屏障,防止编译器/CPU 重排影响正确性。
注意:volatile 不保证原子性(i++ 这类复合操作仍然不安全)。
2. 应用场景
① 状态标志位(最经典)
一个线程修改、其他线程轮询读的开关:
java
volatile boolean running = true;
// 线程 A
while (running) { /* 工作 */ }
// 线程 B
running = false; // 线程 A 能立刻看到,退出循环不加 volatile,线程 A 可能永远看不到 running 的变化(JIT 优化成死循环)。
② 双重检查锁(DCL)中的单例
java
class Singleton {
private static volatile Singleton instance;
public static Singleton getInstance() {
if (instance == null) { // 第一次检查
synchronized (Singleton.class) {
if (instance == null) { // 第二次检查
instance = new Singleton();
}
}
}
return instance;
}
}instance 必须 volatile:防止 new Singleton() 的指令重排序(先赋引用再执行构造),导致其他线程拿到半初始化对象。
③ 并发容器/框架中的"发布"安全
- 无锁队列/状态机里,用 volatile 发布新状态;
- AQS 里的
state用 volatile; - 安全的单次发布(safe publication):对象引用用 volatile 发布,保证其内部字段的可见性。
④ 多线程下的"轻量开关"
如:配置热更新标志、缓存失效标志、中断标志,只要满足"一个线程写、多个线程读,且不依赖复合操作"。
3. 不适用场景
- 需要原子性的复合操作(
count++、i = i + 1)→ 用 AtomicInteger 或锁; - 需要互斥排他的场景 → 用 synchronized/Lock。
一句话总结
volatile 用于"一写多读"的状态标志、DCL 单例、安全发布等场景,解决可见性和有序性问题;不保证原子性,复合操作仍需原子类或锁。