volatile通过强制读写直连主内存并插入内存屏障,确保多线程可见性与禁止指令重排序;仅适用于状态标志、单次赋值引用等简单场景,不保证原子性。

Java 中用 volatile 修饰变量,就能在不加锁的前提下让多线程看到最新值、防止读写顺序被乱调——但它只管这两件事,不管原子性。
怎么写才真正起作用
必须把 volatile 加在变量声明处,且该变量是被多个线程共享读写的:
- 正确写法:private volatile boolean isRunning = true;
- 错误写法:boolean isRunning = true;(没加 volatile,不可见)
- 错误写法:volatile private boolean isRunning = true;(修饰符顺序错,编译不通过)
注意:volatile 只对变量本身有效,不能修饰局部变量、方法或类;也不支持复合操作如 count++ 或 list.add()。
它怎么保证可见性
底层靠的是强制“绕过缓存直连主内存”:
- 写 volatile 变量时,JVM 立即把新值刷进主内存,不留在 CPU 缓存里
- 读 volatile 变量时,JVM 强制从主内存重新加载,不复用工作内存旧副本
- 配合 MESI 缓存一致性协议,其他 CPU 核心能立刻感知到这个变更
所以一个线程改了 isRunning = false,另一个线程 while 循环里每次读都能拿到 false,不会卡死。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
它怎么禁止指令重排
不是靠魔法,而是 JVM 在字节码层面插入内存屏障(Memory Barrier):
- 写 volatile 变量前:加 StoreStore 屏障,确保前面的普通写已落地
- 写 volatile 变量后:加 StoreLoad 屏障,阻止后续读写被提到它前面
- 读 volatile 变量后:加 LoadLoad + LoadStore 屏障,锁定读之后的依赖顺序
比如常见双重检查单例中,instance = new Singleton(); 这行可能被重排为“分配内存→写引用→初始化对象”,加上 volatile 就能堵住这种危险重排。
哪些场景适合用 volatile
典型适用情况有三类:
- 状态标志位:如 shutdownRequested、isInterrupted
- 一次性安全发布:如单例对象引用、配置项初始化完成标记
- 与 CAS 配合使用:AtomicInteger 的 value 字段内部就用 volatile 保证读写可见
不适合场景:计数器(i++)、累加求和、需要锁保护的临界区逻辑——这些必须用 synchronized 或 Atomic 类。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










