volatile不能保证原子性,仅保证可见性(通过mesi协议强制刷新主内存并使缓存失效)和有序性(通过内存屏障禁止指令重排);i++等复合操作因含读-改-写三步且无互斥机制,仍存在丢失更新问题。

因为 volatile 的设计目标不是做“操作锁”,而是解决变量读写在多线程间的同步问题——它管“值能不能被看到”和“指令会不会乱序”,但不管“一连串动作能不能一起完成”。
可见性:让最新值“传得快”
volatile 通过底层的 MESI 缓存一致性协议,强制线程修改变量后立刻写回主内存,并通知其他 CPU 缓存失效。这样,下一次读取时就只能从主内存加载新值。所以,单次读或写操作是立即可见的,比如 flag = true 或 if (stop) 就能立刻生效。
有序性:防止指令“插队”
volatile 在读写前后插入内存屏障(Memory Barrier),禁止编译器和 CPU 把它前后的指令随意调换顺序。这在双重检查锁(DCL)单例中至关重要——避免 new Singleton() 这个对象构造过程被重排,导致其他线程拿到一个尚未初始化完毕的对象引用。
原子性缺失:i++ 是三步,volatile 只保其中两步
i++ 看似简单,实际包含三个不可分割的子操作:
Java JDK 25 来自 OpenJDK 官方归档,版本为 JDK 25,本条下载地址已指向官方 Windows x64 zip 安装包直链,适合调试旧项目或兼容旧版 Java 运行环境。
- 从主内存或缓存中读取当前值(read)
- 在 CPU 寄存器中执行加 1(modify)
- 把结果写回内存(write)
volatile 能保证每次 read 都拿到最新值,每次 write 都立即刷到主内存,但它不锁定整个流程。两个线程可能同时读到 i == 5,各自加 1 后都写回 6,最终只累加了一次。这个“读-改-写”链条中间没有互斥机制,因此必然丢失更新。
什么操作 volatile 能原子保证?
仅限于单次读或单次写本身,例如:
- boolean running = true;
- int status = 1;
- long id = 123456789L;(注意:64位 long/double 在 JVM 早期版本中非原子,但现代 JVM + volatile 已保证其读写原子)
只要不涉及“读+算+写”的复合逻辑,volatile 就能安全使用。一旦需要计数、累加、状态切换依赖旧值,就必须升级为 synchronized、Lock 或 AtomicInteger。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










