当前位置: 首页 > news >正文

【面试题-多线程】什么是 ABA 问题,怎么产生的,怎么解决?

一篇吃透CAS的ABA问题:成因、风险与全套解决方案

前言💡

并发编程中我们经常使用CAS(Compare And Swap)实现无锁并发,相比重量级synchronized拥有更高吞吐量。很多开发者熟练使用CAS,却忽略它经典的ABA漏洞
本文循序渐进讲清楚:

  1. 什么是ABA问题
  2. ABA如何产生、会造成什么事故
  3. 主流解决方案原理 + 代码示例
  4. 方案优缺点横向对比

一、什么是CAS?快速回顾📚

CAS全称比较并交换,是乐观锁底层原子操作,操作分为两步:

  1. 比较:判断内存当前值 == 预期旧值
  2. 交换:相等则更新为新值;不相等直接失败

伪代码逻辑:

if(内存值==预期旧值){内存值=新值;returntrue;}else{returnfalse;}

注意:原生CAS只对比数值本身,这就是ABA问题的根源!

二、什么是ABA问题?🤔

ABA定义:线程1读取变量值为A,在线程1执行CAS前;变量被其他线程修改为B,随后又被改回A。线程1执行CAS时发现值依旧是A,认为变量没有变动,执行更新,最终引发数据异常。

简单一句话:值看上去没变,但中间被篡改过!

ABA完整时序流程图

内存变量 V=A线程2🟥线程1🟦内存变量 V=A线程2🟥线程1🟦线程1阻塞/失去CPU时间片⏸️值变回A,肉眼看不出变化CAS判定成功,执行覆盖更新!⚠️读取V,获取值A(准备执行CAS)CAS(A→B),修改成功 V=BCAS(B→A),修改成功 V=A恢复运行,执行CAS(A,新值)

三、ABA问题真实场景举例🧨

最经典场景:并发栈无锁操作(单向链表实现栈)
栈结构:A → B → C,栈顶 = A

  1. 线程T1准备弹出栈顶A,读取头结点A;准备执行CAS
  2. T1暂停;线程T2执行出栈:弹出A,栈变成B→C
  3. T2继续把A入栈,栈变回A→B→C
  4. T1恢复执行CAS,发现栈顶依旧是A,执行出栈
    最终链表指针错乱,出现内存丢失、循环链表、数据泄露严重bug!

风险总结

原生CAS只校验数值,无法识别中间变更历史
简单类型(数字)场景ABA危害不直观;链表、对象引用等基于指针的结构,ABA极易引发灾难性BUG

四、ABA问题核心产生原因✅

  1. 基础版本CAS仅比较数据值,不记录变量修改历史;
  2. 变量经历:A → B → A,最终数值复原;
  3. 线程无法区分:【从未修改的A】 vs 【被修改后恢复的A】;

核心痛点:缺少版本标记

五、ABA问题主流解决方案🛠️

方案1:带版本号的CAS(乐观锁版本号机制)

原理

不再只对比数据本身,每条数据附带一个自增version版本号:

  • 每次成功修改变量,版本号version = version + 1
  • CAS条件:旧数据 + 旧版本号 同时匹配,才能更新

时序图:

内存 V=A,version=1线程2🟥线程1🟦内存 V=A,version=1线程2🟥线程1🟦线程1暂停⏸️当前version=3≠1 → CAS失败 ❌获取 V=A,version=1CAS(A,1→B,2) ✔️ V=B,version=2CAS(B,2→A,3) ✔️ V=A,version=3CAS(A,1,新值)

Java中对应实现:AtomicStampedReference(携带戳stamp,等价版本号)

// 初始化 初始值A,版本戳stamp=1AtomicStampedReference<String>atomicRef=newAtomicStampedReference<>("A",1);intoldStamp=atomicRef.getStamp();StringoldVal=atomicRef.getReference();// 其他线程修改A→B→A,stamp自增为3// CAS:值A,版本1,期望匹配booleansuccess=atomicRef.compareAndSet("A","NEW",oldStamp,oldStamp+1);// 版本不匹配,返回false,成功规避ABA

方案2:AtomicMarkableReference(布尔标记)

存储一个boolean mark标记,只能区分「是否被修改过」,无法记录修改次数
局限性:多次修改后标记会反复翻转,不能彻底杜绝ABA,适用场景有限。

方案3:数据库乐观锁 version字段

业务开发最常用!数据表增加version字段

-- 更新时带上版本条件UPDATEuserSETbalance=balance-100,version=version+1WHEREid=1ANDversion=#{oldVersion};

方案4:使用重量级锁(兜底方案)

直接抛弃无锁CAS,使用synchronized/ReentrantLock,同一时间只允许一个线程操作,从根源杜绝并发竞争。
缺点:并发性能下降,失去无锁优势。

方案5:使用GC+不变对象(不推荐)

每次修改新建对象,不复用旧对象引用,成本极高,极少使用。

六、方案优劣横向对比📊

方案能否彻底解决ABA性能适用场景
AtomicStampedReference(版本戳)✅ 完全解决Java内存无锁并发
AtomicMarkableReference❌ 不完全解决只关心是否改动,不关心次数
数据库version乐观锁✅ 完全解决中等数据库业务并发更新
synchronized 互斥锁✅ 完全解决较低简单并发,追求稳定不追求极致吞吐

七、常见误区澄清⚠️

  1. AtomicInteger / AtomicLong 会遇到ABA吗?
    会!基础原子类只有数值CAS,没有版本戳。
    但普通数值加减场景ABA很难触发严重故障;链表、队列无锁实现必须规避

  2. 只要用CAS就一定要处理ABA?
    不是。如果业务允许「中间被修改又复原」这种场景,可以不用处理。
    但开发通用无锁数据结构(队列、栈)必须防范。

  3. stamp版本号会溢出吗?
    long型版本戳溢出周期极长,工程上基本不用考虑溢出问题。

八、总结📝

  1. ABA本质:变量先A→B→A,原生CAS只对比数值,无法感知中间变更;
  2. 最大风险:链表、无锁队列等基于引用操作的数据结构;
  3. 标准根治方案:增加自增版本号,使用带版本校验的CAS;Java优先使用AtomicStampedReference;数据库增加version乐观锁;
  4. 简单并发场景,也可以直接使用互斥锁规避并发竞争。

日常业务代码很少手写无锁链表,ABA问题遇到概率不高;但学习并发、阅读JDK源码(Concurrent相关容器)必须理解这个经典并发缺陷。

http://www.jsqmd.com/news/1292386/

相关文章:

  • 静电旋杯喷枪厂商有哪些
  • Electron与WebView2实战:将网页快速打包为Windows桌面应用
  • 磁吸易装+稳定传输,赋能机房U位资产高效智能管理
  • 网络工程师转型指南:Python自动化核心工具与实战案例解析
  • RC电路充电时间计算:从理论公式到工程实践的全面解析
  • Python QQ机器人开发实战:从零搭建自动化消息推送系统
  • C#调用Windows API控制光驱托盘:P/Invoke与MCI命令实战
  • Python Pillow图像批处理工具开发:从原理到生产实践
  • SD卡协议栈深度解析:从物理层到文件系统的嵌入式存储驱动实践
  • Transformer解码器架构设计与优化实践
  • NET生态下 OAuth2.0+OIDC 统一身份平台搭建,解决多系统登录互通难题
  • 2026 年新消息:江山正规的不锈钢桥架公司哪家好,藏在工程隐蔽处的这玩意儿,竟能帮你避开十年电路大修的大麻烦? - 企业推荐官【认证】
  • Llama-3与vLLM部署优化:消费级显卡高效运行指南
  • 2026商家支付全链路解决方案拆解,附线上线下真实落地案例
  • 7月钉飞企AI混战:存量格局难破,谁能让AI为企业真正增收?
  • 专科生论文降AI率工具测评与实操指南
  • S7-1200五轴伺服系统PLC控制方案与调试技巧
  • 动态住宅IP技术解析:9000万节点与99.9%成功率的架构密码
  • STM32 OLED多级菜单GUI实现:轻量级嵌入式界面设计实战
  • 自考04747 Java程序设计笔记:面向对象、异常处理与集合框架实战解析
  • PX4与Matlab/Simulink联合仿真:无人机飞控算法开发与验证指南
  • Java 后端转型大模型:Demo 能跑不等于能上线
  • 2026 年新消息:百色评价高的50立方LNG储罐回收厂家哪家强,旧场地里闲置的这个大家伙,居然能换来一笔可观的周转金? - 行业鉴选官
  • 2026年寄大件最便宜的物流公司是哪家?实测对比告诉你答案 - 快递物流资讯
  • 有录网 2026 留学服务口碑榜单分析
  • 方法论把 AI 意识评测从诚实基线推到可发布:一段不刷分的工程实录
  • STM32 G4 ADC高精度采集实战:从硬件过采样到软件滤波全解析
  • 51单片机循迹小车:从硬件选型到PID算法,嵌入式入门实战指南
  • MATLAB与CPLEX在微电网储能优化中的应用
  • STM32CubeMX配置通用定时器PWM驱动舵机:从原理到工程实践