volatile保证可见性靠内存屏障、禁止重排序和强制刷新缓存协同实现,写操作立即刷回主内存并使其他缓存失效,读操作强制从主内存加载最新值,但不保证复合操作原子性。

volatile 保证可见性的核心,不是靠锁或阻塞,而是通过内存屏障(Memory Barrier)+ 禁止指令重排序 + 强制刷新缓存三者协同实现的。
volatile写操作:立即刷回主内存
当一个线程对volatile变量执行写操作时,JVM会插入一个StoreStore屏障(写-写屏障),确保该写操作之前的所有普通写操作都已提交到主内存;紧接着插入一个StoreLoad屏障,强制将当前线程工作内存中该volatile变量的最新值立即写入主内存,并使其他CPU缓存中该变量的副本失效。
- 不是“慢慢同步”,而是“写完立刻可见”
- 不保证原子性(如i++仍需synchronized或AtomicInteger)
- 底层常对应x86的lock xadd或mfence指令
volatile读操作:强制从主内存加载
当一个线程读取volatile变量时,JVM会插入一个LoadLoad屏障(读-读屏障),再插入一个LoadStore屏障,确保该读操作之后的普通读/写不会被重排到它前面;更重要的是,它禁止使用寄存器或本地缓存中的旧值,必须从主内存(或通过MESI协议获取最新值)重新读取。
- 每次读都是“新鲜”的,不会命中过期缓存
- 读操作本身不加锁,开销远小于synchronized
- 配合写操作,构成“一个线程写 → 主内存更新 → 其他线程读 → 强制拉新”的可见链
volatile为什么不能保证原子性?
可见性 ≠ 原子性。比如volatile int count = 0;,执行count++实际分三步:读count、加1、写回count。虽然每一步的读和写都可见,但中间可能被其他线程打断——两个线程同时读到0,各自加1后都写回1,结果丢失一次更新。
立即学习“Java免费学习笔记(深入)”;
- volatile只保证单个读或单个写的原子性(Java内存模型规定long/double非volatile时可能有半个字问题,volatile可避免)
- 复合操作(read-modify-write)天然非原子,需用synchronized、Lock或java.util.concurrent.atomic包
volatile的典型适用场景
适合状态标志、一次性安全发布、双重检查锁中的实例引用等无需复合操作、仅需状态通知的场合。
- 线程控制开关:volatile boolean running = true;,另一线程设为false后,原线程能立即看到
- 单例模式中防止指令重排序:volatile Singleton instance;,避免new对象过程被重排导致其他线程拿到未初始化完成的对象
- 不适用于count++、list.add()等需要读-改-写语义的操作
基本上就这些。volatile的可见性是JMM在硬件层与编译器层共同保障的结果,理解它关键在于抓住“写即刷出、读必重载、禁止重排”这三点,而不是把它当成轻量级锁来用。










