CAS解决多线程更新共享变量时丢数据的问题,如两个线程同时对计数器加1,普通i++会丢失一次更新,而CAS通过“读—比—换”三步(读当前值、比预期值、一致则换新值)确保原子性;Java中通过AtomicInteger等原子类封装实现,简洁安全,但存在ABA问题、忙等开销大、仅支持单变量原子操作三大限制。

直接从“它解决什么问题”切入,别一上来就啃原理。CAS不是为炫技存在的,它是为解决 多线程更新共享变量时丢数据 这个具体痛点而生的——比如两个线程同时对计数器加1,用普通 i++ 会只加一次,用 CAS 就能稳稳加两次。
CAS 的核心动作就三步
它不锁资源,而是靠“核对再动手”:
- 读当前值(比如内存里是 10)
- 比预期值(你手里记着“应该还是 10”)
- 换新值(确认没变,才把 10 → 11;若已变成 12,就放弃这次,重读重试)
Java 里最常用的入口是 AtomicXXX 类
不用自己调 Unsafe,日常开发直接用封装好的原子类就行:
你接手一个需求时,是不是经常这样:"改一个小字段 → 结果把不相关的代码也改了"、"需求说得很模糊 → 做着做着发现跑偏了"、"数据库加个字段 → 上线才发现漏了数据兼容"、"做了个新功能 → 一个月后自己都忘了当时怎么设计的"、"写到一半被中断 → 再回来不知道从哪继续";这个 Skill 就是专门解决这些问题的。 它会自动探测你的项目环境(JDK、Spring Boot、ORM、数据库、前端框架),记在
AtomicInteger count = new AtomicInteger(0);-
count.incrementAndGet();—— 这一行背后就是循环 + CAS,安全又简洁 - 类似还有
AtomicLong、AtomicReference(支持对象引用),按需选
必须知道它三个典型软肋
理解优点容易,看清限制才真懂怎么用:
-
ABA 问题:值从 A→B→A,CAS 以为没动过,其实中间被改过。解法是加版本号,用
AtomicStampedReference - 忙等开销:失败就重试,若竞争激烈,CPU 白跑循环。不适合高冲突场景
- 只能保单变量:不能原子更新两个字段(如账户余额+最后操作时间),得用锁或更复杂结构
和 synchronized 不是对立关系,而是分工关系
CAS 不是“取代锁”,而是“在合适的地方绕过锁”:
- 简单数值更新(计数、状态标志)、低竞争场景 → 优先用 CAS,轻量高效
- 涉及多个变量、复杂逻辑、或写操作远多于读操作 → 锁更稳妥,避免无限重试
- 现代 JDK 中两者常配合:比如
ReentrantLock底层获取锁时,就先用 CAS 尝试快速抢锁,失败再进队列
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










