Skip to content

volatile关键字

一、是什么?

volatile是Java中的关键字,用于修饰变量。它通过以下机制确保多线程环境下的数据安全:

  1. 可见性:当一个线程修改volatile变量时,其他线程能立即看到最新值。
  2. 禁止指令重排序:防止编译器和CPU优化时打乱指令顺序(通过内存屏障实现)。

二、解决什么问题

  1. 内存可见性问题
    默认情况下,线程操作变量时可能从本地缓存(如CPU寄存器)读取旧值,导致其他线程的修改不可见。
    示例问题:线程A修改共享变量flag,线程B因缓存未更新而读取旧值。
    volatile强制所有读写直接操作主内存,保证可见性。

  2. 指令重排序问题
    编译器/CPU可能调整无关指令的执行顺序以提高性能,但在多线程下可能导致逻辑错误。
    示例问题:单例模式中,未初始化完的对象被其他线程使用(双重检查锁定失效)。


三、应用场景

  1. 状态标志位
    简单布尔标志(如停止线程的isRunning),无需原子性操作。

    java
    volatile boolean isRunning = true;
    
    void stop() { isRunning = false; } // 线程A调用
    void task() { while (isRunning) { ... } } // 线程B读取
  2. 单例模式(双重检查锁定)
    确保对象初始化完成后再被访问(JDK 5+生效)。

    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;
        }
    }
  3. 独立观察的变量
    变量被多个线程读取,但仅由单个线程写入(如配置更新)。


四、Java示例

可见性演示

java
public class VolatileDemo {
    volatile int counter = 0; // 移除volatile会导致死循环

    public static void main(String[] args) throws InterruptedException {
        VolatileDemo demo = new VolatileDemo();
        
        new Thread(() -> {
            while (demo.counter == 0) {} // 循环检测
            System.out.println("Counter changed!");
        }).start();

        Thread.sleep(1000);
        demo.counter = 1; // 主线程修改
    }
}

五、与synchronized的区别

特性volatilesynchronized
作用范围仅修饰变量修饰方法/代码块
原子性❌ 不保证(如i++✅ 保证
可见性✅ 保证✅ 保证
有序性✅ 禁止重排序✅ 保证
线程阻塞❌ 不阻塞✅ 阻塞(重量级锁)
性能开销较高

六、重要注意事项

  1. 不保证原子性
    volatile无法解决复合操作(如count++)的线程安全问题。需改用AtomicIntegersynchronized
    错误示例

    java
    volatile int count = 0;
    count++; // 非原子操作(读取+修改+写入)
  2. 适用场景有限
    仅适用于满足以下条件的场景:

    • 变量独立于其他状态(不依赖旧值)。
    • 写操作不依赖当前值(如直接赋值flag=true)。
  3. JDK 5+的内存模型改进
    volatile的语义在JDK 5中通过JSR-133被强化(增强有序性保证),旧版本行为可能不一致。

  4. 替代方案

    • 需要原子性 → 使用java.util.concurrent.atomic包(如AtomicInteger)。
    • 复杂同步 → 使用ReentrantLocksynchronized

七、总结

volatile是轻量级的线程同步工具,核心解决可见性有序性问题,但不保证原子性。适用于状态标志、单例模式等简单场景。在JDK 5+中,其语义通过内存屏障严格实现,但需谨慎评估是否满足原子性需求。对于复杂操作,优先考虑原子类或显式锁机制。