← 每日面试题 学习看板

什么是CAS?存在什么问题?

面试题/00java/02Java 并发编程/03原子操作与CAS/什么是CAS?存在什么问题?.md

面试记录 2026-09-26

题目:什么是CAS?存在什么问题?

难度:low

标签:java/cas, general/knowledge

评分:⭐⭐⭐☆☆

我的回答

CAS 其实是对线程安全问题的一种处理方式,它本身的处理方式指的是比较,然后交换。如果比较的过程中发现比较的对象发生了变化,就先不做处理,进行再一次比较,然后再去进行处理,然后确保修改修改的时候是符合自身预期的,然后来实现线程安全的保障。但是它本身存在一个所谓 ABA 的问题。我修改前这个目标是 A,但是中间的过程中有另一个线程把目标修改为了 B,而我修改的时候预期是把 A 修改成其他的,但是它已经是 B 了。而这中间又出现了一个线程,把这个 B 改成了 A,但是我修改的时候看到的还是 A。实际上本身预期是我从 A 改到另一个值,但实际上我改的是有一个人把 A 改成了 B,另一个人把 B 又改成了 A。我修改的实际内容并不是我原本预期的,这就是 CAS 中最常见的,也是最核心的问题,ABA 问题。它处理的时候可以使用版本号,就不存在 ABA就是你每次只能往下更改,不会说 A 又能改回去的情况。

点评

优点:准确抓住 CAS = Compare And Swap 的本质;ABA 问题描述清晰(A→B→A 全过程);正确给出版本号解决方案

不足:只覆盖 ABA 一个痛点,遗漏自旋开销、单变量原子性;未说明 CAS 在 OS 层的实现(cmpxchg 硬件指令);未提 AtomicStampedReference 官方实现

补充:三要素 expected/actual/new;三大痛点 ABA、自旋开销、单变量原子性;AtomicStampedReference 是版本号的官方实现

完整讲解

第一部分:知识重点剖析

核心考点定位:能否说清 CAS 的三要素、OS 层面实现,以及三个常见痛点。

知识点拆解:

  1. 底层机制:CAS 全称 Compare And Swap,三个要素:

只有当 actual == expected 时才把内存改为 new,否则什么都不做(CAS 失败,通常自旋重试)

  1. OS/硬件层面:靠 CPU 的原子指令实现,x86 上是 cmpxchg,单条指令完成比较+交换,不会被中断打断;Java 里通过 Unsafe 或 VarHandle 调用,是用户态的"无锁"原语
  2. 三大痛点:
  1. 典型应用:AtomicInteger/AtomicLong(计数器)、AtomicReference(引用计数)、ConcurrentHashMap 的 put(cell 级别的 CAS)
按「底层原理 → 设计权衡 → 工程实践」递进排列。

第二部分:考察方向与延伸递进

考察方向:

延伸递进面试题:

  1. ABA 问题在工程里真的遇到过吗?怎么发现的?
  1. CAS 和 synchronized 怎么选?
  1. LongAdder 和 AtomicLong 的区别?

第三部分:面试者参考回答(300-600 字口语化)

面试官您好,CAS 全称 Compare And Swap,是并发编程里最基础的无锁原子操作。

它的三个要素是 expected、actual 和 new:线程先读一下内存值,作为 expected;如果内存中的实际值 actual 等于 expected,就把内存改成 new;否则什么都不做,通常自旋重试。CAS 之所以能"无锁",是因为它依赖 CPU 的原子指令,x86 上是 cmpxchg,一条指令完成比较+交换,不会被中断打断,也不用进内核态拿锁。

CAS 有三个常见的问题:

第一是 ABA 问题。我先看到值是 A,想把它改成 C;但我准备执行 CAS 的这段时间里,另一个线程把 A 改成了 B,紧接着又把它改回了 A;这时候我的 CAS 看到还是 A,就成功了,但实际上这个"A"已经和当初的"A"不是同一个东西了,中间的业务语义全错了。解决方案是引入版本号,比如 Java 的 AtomicStampedReference 就是"值 + 版本号"配对,每次修改都让版本号递增,ABA 自然被识别出来。

第二是自旋开销。CAS 失败要重试,如果竞争激烈,线程就一直自旋占着 CPU,不像锁那样会阻塞让出。极端情况下 CPU 会被打满。工程上遇到这种场景常用 LongAdder,它把累加器拆成 Cell 数组,多线程各写各的分段,读的时候再汇总。

第三是单变量原子性。CAS 只能保证一个变量的原子,如果你要做 a++ 和 b-- 这种复合操作,CAS 管不住,还是得回到 synchronized 或者用复合类型的原子方法。

典型应用上,AtomicInteger、AtomicLong、AtomicReference 都是基于 CAS 的,ConcurrentHashMap 的 put 也是靠 cell 级别的 CAS 来保证并发安全。

这就是我对 CAS 的理解。