好的,我来帮你整理一份 Java 中 volatile 关键字详解,从概念、原理、使用场景到注意事项,深入讲解并配示例代码。


🔹 1. volatile 简介

  • 类型:Java 关键字
  • 作用:确保 多线程环境下的可见性 和 防止指令重排
  • 主要用于 轻量级同步,替代部分 synchronized 的场景

🔹 2. volatile 的核心特性

  1. 可见性(Visibility)
    • 一个线程修改了 volatile 变量,立即对其他线程可见
    • 普通变量在多线程下可能会被 CPU 缓存,其他线程不一定能立即看到
  2. 禁止指令重排序(Ordering)
    • 编译器和 CPU 在优化时可能会改变指令执行顺序
    • volatile 会在 读/写操作前后加入内存屏障(Memory Barrier),保证顺序
  3. 不保证原子性(Atomicity)
    • 自增 count++ 等操作不是原子操作
    • 对单次写入(赋值)是原子的,但复合操作需要额外同步

🔹 3. 使用场景

  1. 状态标志(Flag)
class Task implements Runnable {
    private volatile boolean running = true;

    public void stop() {
        running = false;
    }

    @Override
    public void run() {
        while (running) {
            // 执行任务
        }
        System.out.println("线程已停止");
    }
}

  • 一个线程修改 running,其他线程可以立即感知
  1. 单例模式(Double-Check Locking)
public class Singleton {
    private static volatile Singleton instance;

    private Singleton() {}

    public static Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

  • volatile 防止 对象未完全初始化就被其他线程访问

🔹 4. 内存模型(JMM)相关

  • volatile 与 Java 内存模型(JMM) 密切相关
  • 保证:
    • 写操作先于后续读操作
    • 写入的值对所有线程立即可见
  • CPU 缓存和寄存器的优化不会影响 volatile 变量

🔹 5. 代码示例:可见性演示

class VolatileDemo {
    private static volatile boolean flag = true;

    public static void main(String[] args) throws InterruptedException {
        new Thread(() -> {
            while (flag) {
                // 循环等待 flag 变为 false
            }
            System.out.println("线程结束");
        }).start();

        Thread.sleep(1000);
        flag = false; // 主线程修改 flag
        System.out.println("主线程修改 flag");
    }
}

  • 如果去掉 volatile,子线程可能 永远循环
  • 加上 volatile,子线程能及时感知变化

🔹 6. 注意事项

  1. 不能保证复合操作原子性
volatile int count = 0;
count++; // 不安全,可能丢失更新

  • 复合操作需用 synchronized 或 AtomicInteger
  1. 适用场景有限
    • 适合 状态标志、读多写少的场景
    • 不适合 计数器、累加器等高并发写操作
  2. 与 synchronized 对比
    | 特性 | volatile | synchronized |
    |—————–|—————–|——————|
    | 可见性 | ✔ | ✔ |
    | 原子性 | ✘ | ✔ |
    | 性能 | 高 | 相对低 |
    | 适用场景 | 状态标志、单例 | 复合操作、方法同步 |

✅ 总结

  • volatile 是 轻量级同步工具,主要解决 可见性和顺序问题
  • 单次写入原子,但复合操作不保证原子性
  • 常用于 标志位、DCL单例模式 等场景
  • 高并发计数器等需要 AtomicXXX 或 synchronized