volatile不能保证复合操作原子性,因其仅保障单次读/写可见性与有序性,无法约束“读—改—写”多步操作的整体不可分割性;count++等操作会被拆为读、算、写三步,中间计算不受控,导致丢失更新。

volatile 不能保证复合操作的原子性,因为它只管“单次读”或“单次写”的可见与有序,不管“读—改—写”这一整套动作能不能被拆开。
volatile 保证什么
它确保两点:
- 可见性:一个线程写完 volatile 变量,新值立刻刷到主内存;其他线程读时,一定从主内存取,不会用旧缓存值;
- 有序性:在该变量前后插入内存屏障,阻止编译器和 CPU 把相关指令乱序执行。
但它不锁任何东西,也不干预多步操作之间的穿插。
复合操作为什么不行
像 count++、value += 1 或 flag = !flag 这类操作,在 JVM 层面会被拆成至少三步:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 读取当前值(getstatic)
- 在寄存器里计算(iadd、iconst_1、ixor 等)
- 把结果写回变量(putstatic)
volatile 只能保证第一步和第三步直通主内存,中间那步计算完全在本地进行,且不受保护。两个线程可能同时读到 count == 5,各自加 1 后都写回 6——一次更新就丢了。
真正需要原子性的场景怎么办
必须用能覆盖整个操作生命周期的机制:
- AtomicInteger 等原子类:底层调用 CAS 指令,把“读—比—换”压成一条 CPU 级不可中断操作,失败就重试;
- synchronized:把整个复合逻辑包进临界区,靠互斥锁强制串行执行;
- ReentrantLock:提供更灵活的锁控制,同样可保障代码块整体原子性。
单纯加 volatile,就像给门装了透明玻璃(大家都能看见里面),但没上锁——谁都能推门进来,还可能撞在一起。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










