CAS中的ABA问题

如果不理解CAS操作,可以看看我之前写的博客----CAS操作的基本原理

1、什么是ABA问题

CAS中的关键,就是先用内存中的值和旧的预期值进行比较,如果相同,则交换内存中的值和新值。如果不相等,则什么都不做。

比较其实就判断内存中的值是否被改变,如果相同,则认为没发生改变。但是这种结论是存在一定的漏洞的。因为内存中的值和旧值相同,可能确实没有发送改变,但也有可能改变了,最终又变回来了。

例如:

  1. 进程P1在共享变量中读到值为A
  2. P1被抢占了,进程P2执行
  3. P2把共享变量里的值从A改成了B,再改回到A,此时被P1抢占。
  4. P1回来看到共享变量里的值没有被改变,于是继续执行。

这样的漏洞,在大多数情况下,其实也没啥影响,但在极端情况下也会引起BUG

ABA问题好比我今天去买了个手机,我拿到这个手机,我无法区分,它是一个新机(出厂到现在一直没有使用过),还是一个翻新机(出厂之后已经卖给别人了,使用一段时间后,旧了,被JS回收回来,换了一个壳,当做新机来卖),虽然我拿到的有可能是一个翻新机,但翻新机大多情况下也是能用的,也挺好用的,但是存在少数情况下还是会翻车

举一个经典的例子,ABA问题产生的BUG
冯同学的账户有100,他要去取50。当按下取款的操作的时候,机器卡了一下,冯同学多按了一下取款。这就相当于,一次取钱操作,执行了两遍(两个线程,并发的去执行这个取款操作)。冯同学的预期结果应该是只取成功一次,也就是说希望取走50,账户还剩50。
如果基于CAS的方式来实现这里的取款:

在这里插入图片描述

按照上述的分析,此处就是两个操作,实际只成功一次。此时还没有引入ABA问题。


引入ABA问题

在这里插入图片描述

这里存在两个巧合,导致了ABA问题。

1.一次取钱操作,执行了两边
2.第二次取款前的一瞬间,冯同学的朋友给他转了50

虽然这样的极端的场景出现的概率非常低,作为一个合格的程序员,我们也要进行处理。

2、解决ABA问题

解决ABA问题的思路就是引入一个版本号或者时间戳,这里我们用版本号,这个版本号只能变大, 不能变小,修改变量的时候,比较的就不是变量本身,而是比较版本号

此处要求,每次针对余额进行修改,都让版本号加1,每次修改之前,也要先对比版本号,看看旧版本和当前版本是否一致,如果不一致,则放弃操作。

  • 最开始,CPU1和CPU2以及内存中的版本号都为1。
  • 当t1操作成功后,内存中的版本号为2。
  • 冯同学的朋友转账50,内存中的版本号为3。
  • t2操作,虽然变量值相同,但版本号不同(一个为1,一个为3),则放弃操作。
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值