0

0

Java面试之CAS原理与ABA问题解决方法

幻夢星雲

幻夢星雲

发布时间:2026-01-01 08:57:08

|

984人浏览过

|

来源于php中文网

原创

CAS是CPU提供的原子指令,Java通过Unsafe.compareAndSwapInt等方法暴露,AtomicInteger等类底层依赖它实现无锁更新;其核心是“比较并交换”,仅当内存值等于预期旧值时才更新为新值。

java面试之cas原理与aba问题解决方法

什么是CAS?它在Java里怎么被调用

CAS(Compare-And-Swap)不是Java语言关键字,而是CPU提供的一条原子指令,在Java中通过Unsafe.compareAndSwapInt等底层方法暴露出来。JDK的java.util.concurrent.atomic包里所有AtomicIntegerAtomicReference等类,内部都依赖它实现无锁更新。

典型使用场景是避免加锁做计数器或状态切换:比如多个线程同时对一个计数器+1,用incrementAndGet()synchronized更轻量。

关键点在于:CAS操作有三个参数——内存位置V、旧值A、新值B;仅当V当前值等于A时,才把V设为B,并返回true;否则返回false,不修改V。

常见错误现象:写自定义无锁结构时直接调用Unsafe,却忽略不同JVM版本中Unsafe字段名或获取方式差异(如JDK 9+模块限制),导致NoAccessErrorIllegalAccessException

立即学习Java免费学习笔记(深入)”;

ABA问题到底是什么,为什么它危险

ABA问题不是“值变回去了所以没问题”,而是指:某个变量V初始为A,被线程1读取后,被线程2修改为B又改回A;此时线程1执行CAS判断“还是A”,就误认为没被干扰,继续更新——但中间状态已丢失,逻辑可能出错。

典型场景:AtomicReference用于实现无锁或队列时,节点被弹出(A→B)、回收、再分配(B→A),导致CAS成功却指向了错误内存地址。

Pi智能演示文档
Pi智能演示文档

领先的AI PPT生成工具

下载

这不是理论风险:在高并发对象池、内存复用、链表结构中真实发生过,且极难复现和调试。

注意:AtomicInteger这类纯数值类型一般不构成实质危害(比如计数器从100→101→100,再+1变成101,业务上未必算错),但AtomicReference指向对象引用时,ABA意味着对象身份已变更,必须警惕。

怎么解决ABA?AtomicStampedReference不是万能药

AtomicStampedReference通过给引用搭配一个整型“戳记”(stamp),把CAS从二维(引用)扩展成三维(引用+stamp),每次更新都要求引用和戳记同时匹配。这是最常用的ABA缓解手段。

但要注意几个现实约束:

  • 戳记是int类型,存在溢出回绕风险(虽然概率极低,但金融/长期运行系统需评估)
  • 每次compareAndSet必须传入当前戳记值,不能只靠getStamp()——因为get和CAS之间可能已被其他线程更新,必须用get(int[] stampHolder)原子读取二者
  • 它只解决“是否被改过”的问题,不解决“改成了什么”——如果你需要完整变更历史,得自己记录日志或用AtomicMarkableReference(布尔标记)或自定义结构
AtomicStampedReference ref = new AtomicStampedReference<>(head, 0);
int[] stamp = new int[1];
Node current = ref.get(stamp);
int oldStamp = stamp[0];
// ……处理逻辑
boolean success = ref.compareAndSet(current, newNode, oldStamp, oldStamp + 1);

还有没有更彻底的替代方案

真正规避ABA,核心思路是让“相同值≠相同身份”。除戳记外,还有几种工程化选择:

  • AtomicMarkableReference:适合只需区分“是否被修改过”的场景(如标记节点是否已删除),空间开销更小
  • 不复用对象:在对象池中禁用立即重用,加入延迟释放或GC友好的弱引用缓存,从源头切断ABA路径
  • 换数据结构:某些场景下,用ConcurrentLinkedQueue代替手写无锁队列,它内部用“tail节点两次检查”策略绕过ABA依赖
  • JDK 17+的VarHandle:虽不直接解决ABA,但提供了更安全、标准化的原子访问接口,配合WeakPair等模式可构建更可控的版本控制

别迷信“加个stamp就万事大吉”。实际排查时,先确认你的场景是否真受ABA影响——比如只是计数器,那大概率不需要折腾戳记;如果是自定义无锁容器,就得严格验证ABA路径,并在测试中注入模拟ABA的干扰线程。

相关专题

更多
java
java

Java是一个通用术语,用于表示Java软件及其组件,包括“Java运行时环境 (JRE)”、“Java虚拟机 (JVM)”以及“插件”。php中文网还为大家带了Java相关下载资源、相关课程以及相关文章等内容,供大家免费下载使用。

825

2023.06.15

java正则表达式语法
java正则表达式语法

java正则表达式语法是一种模式匹配工具,它非常有用,可以在处理文本和字符串时快速地查找、替换、验证和提取特定的模式和数据。本专题提供java正则表达式语法的相关文章、下载和专题,供大家免费下载体验。

724

2023.07.05

java自学难吗
java自学难吗

Java自学并不难。Java语言相对于其他一些编程语言而言,有着较为简洁和易读的语法,本专题为大家提供java自学难吗相关的文章,大家可以免费体验。

728

2023.07.31

java配置jdk环境变量
java配置jdk环境变量

Java是一种广泛使用的高级编程语言,用于开发各种类型的应用程序。为了能够在计算机上正确运行和编译Java代码,需要正确配置Java Development Kit(JDK)环境变量。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

395

2023.08.01

java保留两位小数
java保留两位小数

Java是一种广泛应用于编程领域的高级编程语言。在Java中,保留两位小数是指在进行数值计算或输出时,限制小数部分只有两位有效数字,并将多余的位数进行四舍五入或截取。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

398

2023.08.02

java基本数据类型
java基本数据类型

java基本数据类型有:1、byte;2、short;3、int;4、long;5、float;6、double;7、char;8、boolean。本专题为大家提供java基本数据类型的相关的文章、下载、课程内容,供大家免费下载体验。

445

2023.08.02

java有什么用
java有什么用

java可以开发应用程序、移动应用、Web应用、企业级应用、嵌入式系统等方面。本专题为大家提供java有什么用的相关的文章、下载、课程内容,供大家免费下载体验。

429

2023.08.02

java在线网站
java在线网站

Java在线网站是指提供Java编程学习、实践和交流平台的网络服务。近年来,随着Java语言在软件开发领域的广泛应用,越来越多的人对Java编程感兴趣,并希望能够通过在线网站来学习和提高自己的Java编程技能。php中文网给大家带来了相关的视频、教程以及文章,欢迎大家前来学习阅读和下载。

16881

2023.08.03

php源码安装教程大全
php源码安装教程大全

本专题整合了php源码安装教程,阅读专题下面的文章了解更多详细内容。

7

2025.12.31

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Kotlin 教程
Kotlin 教程

共23课时 | 2.1万人学习

C# 教程
C# 教程

共94课时 | 5.7万人学习

Java 教程
Java 教程

共578课时 | 40.1万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号