volatile不能保证原子性,仅保障单次读写可见性与有序性,对i++等读-改-写复合操作无效;其适用场景限于不依赖当前值的单向读或写操作。

volatile 不能保证原子性,因为它只管“值一改就让别人看见”,不管“改的过程能不能被插队”。原子性要求一个操作不可分割、中间不被打断,而 volatile 完全不提供这种排他控制。
volatile 只保障单次读或写,不保障复合操作
像 i++ 这样的操作,在 JVM 层面实际拆成三步:读取当前值 → 在本地加 1 → 写回内存。volatile 能确保每次读取都拿到主存最新值,每次写入都立刻刷到主存,但它无法把这三步锁在一起执行。两个线程可能同时读到 i = 5,各自加 1 后都写回 6,结果一次累加就丢了。
- 赋值语句 i = 10 是原子的,volatile 对它天然有效
- 但 i++、i += 1、i-- 等都属于“读-改-写”复合操作,volatile 无能为力
- 字节码中对应 getstatic → iadd → putstatic,volatile 仅作用于首尾两条指令
底层没有互斥机制,只有内存屏障
volatile 的实现依赖内存屏障(如 StoreLoad 屏障),它的作用是:
- 禁止编译器和 CPU 对相关读写指令重排序(保障有序性)
- 强制刷新缓存、使其他 CPU 缓存行失效(保障可见性)
- 但它不加锁、不阻塞线程、不协调执行顺序——没有互斥,就没有原子性
相比之下,synchronized 会获取监视器锁,CAS 操作由 CPU 硬件指令(如 x86 的 lock xadd)直接保证整套流程不可分割。
立即学习“Java免费学习笔记(深入)”;
适用边界很明确:只读/只写,不依赖旧值
volatile 的安全使用场景,必须满足两个条件:
- 操作是单向的:要么只 set,要么只 get
- 写入不依赖当前值:比如状态标志位 volatile boolean running = true,设置为 false 就是最终态,不需要先读再判断
一旦出现“根据当前值决定下一步怎么写”,例如计数、开关切换、引用替换(非 final 字段),就必须换用 synchronized、ReentrantLock 或 AtomicInteger 等真正支持原子语义的工具。
不复杂但容易忽略:volatile 是可见性的信使,不是操作的守门人。


















