经典的ABA问题与解决方法

针对ABA问题做了一下总结和尝试解决

背景

在学习乐观锁、悲观锁时,了解到CAS是一种乐观锁的实现,但是从博客中看到说CAS会存在ABA问题,于是就搜索了一番。

什么是ABA问题

来自blog 考虑如下操作: 并发1(上):获取出数据的初始值是A,后续计划实施CAS乐观锁,期望数据仍是A的时候,修改才能成功 并发2:将数据修改成B 并发3:将数据修改回A 并发1(下):CAS乐观锁,检测发现初始值还是A,进行数据修改 上述并发环境下,并发1在修改数据时,虽然还是A,但已经不是初始条件的A了,中间发生了A变B,B又变A的变化,此A已经非彼A,数据却成功修改,可能导致错误,这就是CAS引发的所谓的ABA问题。

这个应该就是产生ABA问题的真正原因。

ABA问题的举例

看了几篇讲述ABA问题的博客,如下描述。

  1. 某人取款,由于机器不太好使,多点了几次取款操作。后台threadA和threadB工作,此时threadA操作成功(100->50),threadB阻塞。正好某人朋友打款50元给小牛(50->100),threadC执行成功,之后threadB运行了,又改为(100->50)。 lz钱哪去了???来自blog

个人觉得这里threadB后来继续运行后,总共是会取出两次钱的。

  1. 假设有个线程A去判断账户里的钱此时是15,满足条件,直接+20,这时候卡里余额是35。但是此时不巧,正好在连锁店里,这个客人正在消费,又消费了20,此时卡里余额又为15,线程B去执行扫描账户的时候,发现它又小于20,又用过cas给它加了20,这样的话就相当于加了两次,这样循环往复肯定把老板的钱就坑没了!来自blog

个人觉得评论中这个例子更合适,但不知道该如何在代码中复现,所以还是按照上述的逻辑进行了复现。 A线程首先获取余额是15,然后准备加上20,在A线程还没提交的时候,此时B线程进入,将余额加上20并且成功提交,此时余额为35。但是紧接着用户又消费了20,所以余额还是15,终于A线程获取到了时间片,它比对之后发现余额还是15,所以A线程就执行了。

ABA问题的本质

ABA问题的根本在于CAS在修改变量的时候,无法记录变量的状态,比如修改的次数,是否修改过这个变量。这样就很容易在一个线程将A修改成B时,另一个线程又会把B修改成A,造成CAS多次执行的问题。

示例

来自blog 一家火锅店为了生意推出了一个特别活动,凡是在五一期间的老用户凡是卡里余额小于20的,赠送20元,但是这种活动每人只可享受一次

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值