CAS不是锁,而是通过CPU指令(如x86的CMPXCHG)将“比较+交换”原子化实现无锁并发;它本质是乐观的条件写入,适用于高读低写场景,但存在ABA问题、仅支持单变量原子更新等局限。

CAS 不是锁,但它能实现“不加锁却保证原子性”的效果。关键在于它把“判断+赋值”这个原本两步的操作,压进一条 CPU 指令里执行,中间不可打断,也不依赖 JVM 层面的线程调度或监视器(monitor)机制。
CAS 的本质是“条件写入”
它不是在抢资源,而是做一次“确认后提交”: - 读取变量当前值 V - 比较 V 是否等于你预期的值 A - 如果相等,才把 V 改成新值 B;否则什么也不改,只返回当前真实值 整个过程对外表现为一个不可分割的动作,这就是“无锁原子性”的来源。
- 它不阻塞线程,失败后由调用方决定重试、放弃或改策略
- 适用于高读低写、冲突不频繁的场景,比如计数器、状态标记、简单引用更新
- Java 中通过 Unsafe.compareAndSwapInt/Long/Object 等 native 方法暴露,AtomicInteger 等类都基于它封装
底层靠 CPU 指令硬保证原子性
JVM 自己做不到原子比较并交换,真正起作用的是硬件。以主流 x86 架构为例:
- CMPXCHG 指令完成“比较并交换”全过程:把寄存器值和内存值比对,一致则写入,不一致则加载内存最新值回寄存器
- 为防止多核并发时缓存不一致,CPU 会自动加 缓存锁(cache lock)——仅锁定当前缓存行,开销小;只有在无法缓存时才退化为总线锁
- 指令执行期间还隐式插入内存屏障(memory barrier),禁止编译器和 CPU 对相关读写重排序
为什么说它是“乐观”而非“悲观”
传统 synchronized 是悲观锁:默认认为会有冲突,一上来就加锁、挂起其他线程;CAS 是乐观锁:默认没人动,先干再说,冲突了再处理。
- 没有锁升级、没有 MonitorEntry/Exit 开销,也没有线程上下文切换成本
- 但高竞争下可能反复自旋(如 AtomicLong 在多核激烈更新时),白白消耗 CPU
- 它只能保障单个变量的原子更新,不能像 synchronized 那样包裹一段逻辑代码块
CAS 不是万能的,得知道它的边界
它解决的是“单变量原子更新”,不是“任意并发逻辑安全”。典型局限包括:
立即学习“Java免费学习笔记(深入)”;
- ABA 问题:值从 A→B→A,CAS 误判为没变,但实际上中间状态已不同(可用 AtomicStampedReference 解决)
- 只能单点操作:无法原子更新两个字段(比如账户余额 + 日志时间戳),得靠更上层方案如事务或锁
- 需要调用方配合重试逻辑:比如 AtomicInteger.incrementAndGet() 内部就是循环 CAS,直到成功为止


















