CAS是CPU提供的原子指令(如x86的cmpxchg),Java通过Unsafe暴露,AtomicInteger等仅为封装;它实现乐观同步,核心逻辑是“仅当内存值仍为预期旧值时才写入新值”,本质借硬件之力而非JVM发明。

回答 CAS 面试题拿高分,关键不是堆砌定义,而是展现三层能力:**能说清本质、能辨场景差异、能讲透取舍逻辑**。面试官想看的不是“背过”,而是你是否真正理解它为什么存在、在哪儿该用、又为什么不能乱用。
一、被问“什么是CAS”,别只答定义
直接说“Compare-And-Swap,比较并交换”是及格线;高分回答要立刻带出设计意图和硬件根基:
- 它本质是CPU提供的原子指令(x86是cmpxchg,ARM是ldrex/strex),Java通过Unsafe.compareAndSwapInt暴露,AtomicInteger等类只是封装层
- 不是Java语言特性,也不是JVM发明的——是借硬件之力实现的乐观同步原语
- 核心动作就一句:“只有内存值还是我读到的那个旧值,我才敢写新值;否则说明被别人动过了,我就不写”
二、被问“CAS 和 synchronized 有什么区别”,要对比着讲代价
不能只说“一个无锁一个有锁”,要落到线程行为和系统开销上:
- synchronized:抢不到锁就挂起(进入阻塞态),触发用户态→内核态切换,上下文切换成本高;适合临界区较长、竞争较激烈的场景
- CAS:抢不到就自旋重试(忙等),不切状态、不挂起,但会空耗CPU;适合临界区极短(比如++操作)、冲突概率低的场景
- 补充一句加分项:现代JVM中synchronized其实也用了CAS做锁升级的底层支撑(偏向锁撤销、轻量级锁加锁都靠CAS更新Mark Word)
三、被问“ABA问题怎么解决”,必须区分真假问题
很多候选人一提ABA就慌,其实它在多数业务代码里根本不是问题:
立即学习“Java免费学习笔记(深入)”;
- 先点明前提:ABA不是bug,是语义风险。AtomicInteger做计数器时A→B→A,结果仍是+1,完全正确;但AtomicReference指向链表节点时,A节点被弹出→回收→新对象复用同一地址→再CAS成功,就可能跳过本该处理的中间状态
- 解决方案要对应场景:
- 需要版本控制:用AtomicStampedReference,把值和stamp打包CAS
- 只需标记是否被改过:用AtomicMarkableReference(布尔标记)
- ConcurrentLinkedQueue等JUC类内部已处理,你日常用AtomicInteger/Long基本不用操心
四、被问“CAS有哪些局限”,要体现工程判断力
光说“ABA、自旋开销、只能单变量”是基础分;高分答案得补一句“所以JDK怎么绕过它”:
- 多变量原子更新?→ 用LongAdder分段累加,或把多个字段封装进一个对象,用AtomicReference
整体CAS - 自旋太久浪费CPU?→ LongAdder在竞争激烈时自动扩容cell数组,把自旋分散到多个变量上
- 无法替代所有锁?→ 对,所以AQS用CAS控制state变更,但队列入队/出队失败后仍会挂起线程——CAS负责快速路径,锁机制兜底慢路径


















