Skip to content

P20 volatile 有哪些应用场景 ​

面试题:volatile 是什么?有哪些使用场景?

1. volatile 是什么 ​

volatile 是 Java 提供的轻量级同步机制,两个核心语义:

  1. 可见性:一个线程修改 volatile 变量后,其他线程立即可见(写后强制刷新主内存,读前强制从主内存读取);
  2. 禁止指令重排序: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 单例、安全发布等场景,解决可见性和有序性问题;不保证原子性,复合操作仍需原子类或锁。

基于 VitePress 重建