cas本身不保证内存可见性,其可见性依赖volatile修饰:volatile读确保从主存加载最新值,volatile写确保新值刷回主存并失效其他缓存,配合内存屏障禁止重排序。

CAS 操作本身不直接提供内存可见性,但它与 volatile 语义协同工作,才能在多线程下真正保证可见性。
CAS 依赖 volatile 的读写语义
AtomicInteger 等原子类的底层字段(如 value)被声明为 volatile。这意味着:
- CAS 的“读取当前值”操作,本质是 volatile 读 —— 强制从主内存加载最新值,跳过线程本地缓存;
- CAS 成功后的“写入新值”操作,本质是 volatile 写 —— 立即将新值刷回主内存,并使其他 CPU 缓存中该变量的副本失效;
- JVM 会在 volatile 读/写前后插入内存屏障(LoadLoad、StoreStore 等),阻止指令重排序,确保 CAS 前后的内存操作顺序可见。
单纯靠 CAS 指令无法解决可见性问题
CAS 是一条 CPU 原子指令(如 x86 的 cmpxchg),它只保证“比较+交换”这一步骤不可中断,但不保证:
- 线程 A 执行完 CAS 后,其修改是否立即对线程 B 可见;
- 线程 B 下一次读取时,是否会从自己缓存中取旧值(而不是重新拉取主存);
- 如果没有 volatile 修饰,JIT 编译器甚至可能将循环中对共享变量的重复读取优化为仅读一次(导致死循环或漏响应)。
一个典型对比场景
假设两个线程共享一个 int counter = 0:
- 用普通
int+ 手动 CAS(无 volatile):线程 B 可能永远看不到线程 A 对 counter 的更新,因为读取未强制刷新缓存; - 用
AtomicInteger:内部 value 是 volatile 的,每次get()和compareAndSet()都触发内存同步,线程 B 总能及时看到最新值。
不是 CAS 保证了可见性,而是 volatile 保证了可见性,CAS 利用了它
Java 原子类的设计是“CAS + volatile”的组合策略:
- CAS 提供原子性(执行不中断);
- volatile 提供可见性(值更新即同步)和有序性(禁止重排);
- 二者结合,才完整满足并发三要素 —— 原子性、可见性、有序性。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











