volatile 是 Java 并发编程的”轻量级”同步机制。它真的轻吗?从 CPU 缓存一致性到指令重排序,一篇文章说清楚。

一、为什么要理解 JMM

  • 1.1 物理机缓存模型——CPU → L1/L2/L3 Cache → 主存
  • 1.2 缓存一致性问题——MESI 协议简介
  • 1.3 Java 内存模型(JMM)抽象——主内存 vs 工作内存
  • 1.4 JMM 解决什么——原子性、可见性、有序性

二、volatile 的可见性

  • 2.1 写 volatile 变量——立即刷回主内存
  • 2.2 读 volatile 变量——强制从主内存读取
  • 2.3 一个可见性问题的代码演示
  • 2.4 底层实现——Lock 前缀指令与总线锁/缓存锁

三、volatile 的有序性——禁止指令重排序

  • 3.1 指令重排序的三种类型——编译器重排、CPU 重排、内存系统重排
  • 3.2 happens-before 规则
  • 3.3 volatile 写-读建立的 happens-before 关系
  • 3.4 双重检查锁定(DCL)单例为什么必须加 volatile

四、内存屏障

  • 4.1 Load Barrier / Store Barrier / LoadStore / StoreLoad
  • 4.2 volatile 写前后的屏障插入策略
  • 4.3 volatile 读前后的屏障插入策略
  • 4.4 JVM 层面:OrderAccess::storeload() 的实现

五、volatile 不保证原子性

  • 5.1 i++ 的反汇编分析
  • 5.2 为什么 volatile int count = 0; count++ 在多线程下不安全
  • 5.3 volatile 适用的场景——状态标志、DCL、独立观察

六、volatile 在并发工具中的应用

  • 6.1 AQS 的 state 字段
  • 6.2 ConcurrentHashMap 的 table 数组
  • 6.3 CopyOnWriteArrayList 的数组引用

七、实战案例

  • 7.1 使用 volatile 实现简单的事件监听器
  • 7.2 使用 volatile 实现优雅停机

八、总结与 FAQ

  • volatile vs synchronized 什么时候用哪个
  • 为什么 volatile 不能替代锁