← 每日面试题 学习看板

如何实现无锁化编程?

面试题/00java/02Java 并发编程/09编程实践与应用场景/如何实现无锁化编程?.md

面试记录 2026-10-17

题目:如何实现无锁化编程?

难度:medium

标签:java/concurrency-practice, java/concurrency, general/knowledge

评分:⭐⭐⭐☆☆(3/5)

我的回答

无锁编程的核心手段包括CAS,原子类,无共享状态等; CAS的核心是比较交换,以及原子性的单更新,通过比较预想值,当前值和目标值来实现对于属性更新时确保是从自己知道的改到自己目标的,但是存在ABA问题也就是当前的这个A和自己预期的A本质并不是一个,是其他线程修改后的结果; 原子类是通过cpu包装的原子操作进行对象的简单变更,但是只能应对简单的对象变更增加,并不能应对太复杂的操作; 无共享状态则是基于多线程没有交集,也就不会有线程安全问题,但是共享状态是很多业务所必需的,应用场景相对比较受限;

点评

优点:CAS/原子类/无共享状态三条都答到,ABA 问题点出且解释准确,也意识到"只能处理单变量、简单操作"的边界。

不足:没给具体手段(AtomicInteger/AtomicReference/LongAdder/Unsafe/VarHandle);没说 ABA 的解法(版本号 AtomicStampedReference);没提高并发下的 自旋开销。

补充:无锁 = 乐观重试 + 原子指令;适用"单变量、低到中竞争",高竞争时 LongAdder 优于 AtomicLong,再高就走分段/有锁。

完整讲解

第一部分:知识重点剖析

核心考点定位:无锁的手段清单 + 各自边界 + ABA 治理。

知识点拆解:

  1. CAS:Unsafe.compareAndSwapInt,靠 CPU 的 cmpxchg + lock 前缀保证原子;三要素 expected/update/new,失败重试(自旋)。
  2. 原子类:AtomicInteger/AtomicReference/AtomicLong;高并发计数用 LongAdder(分段 Cell 降低热点)优于 AtomicLong。
  3. 无共享状态:不可变对象(final + 构造期完成)、ThreadLocal、栈封闭。
  4. ABA 治理:AtomicStampedReference(版本号)、AtomicMarkableReference(布尔标记)。
  5. 边界:只能保证单个变量的原子性;自旋在竞争激烈时浪费 CPU;复合操作要 AtomicReference 或直接加锁。

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

考察方向:

延伸递进面试题:

  1. CAS 的 ABA 怎么解决?
  1. LongAdder 为什么比 AtomicLong 快?
  1. CAS 一定自旋吗?竞争大怎么办?

第三部分:面试者参考回答(三步法口语化)

【一句话结论】

面试官您好,无锁化编程本质是"用乐观重试 + 原子指令替代阻塞锁"。

【三点展开】

第一,核心手段是 CAS 和原子类,CAS 靠 CPU 的 cmpxchg 加锁前缀保证原子,失败就自旋重试;

第二,它解决的是单变量的原子更新,复合操作要用 AtomicReference 打包,高并发计数用 LongAdder 分段更好;

第三,还有无共享状态的思路——不可变对象、ThreadLocal,从根上避开竞争。

【一句边界】

当然,CAS 有 ABA 问题要用版本号,而且竞争激烈时自旋反而浪费 CPU——这时不如退回到锁或分段。