CAS分析

一、概念

CAS英文名为 Compare And Swap 中文意思为比较并交换

CAS机制中使用了3个基本操作数,内存地址V,旧的预期值A,要修改的新值B,更新一个变量的时候,只有当预期值A等于内存地址V中的实际值时,才能将内存地址V对应的值改位B

举例:在内存地址V中,存储着值为10的变量,此时,线程1想要对变量值加1,对线程1来说预期值为10,更新值为11,若在线程1要提交更新之前,线程2抢先修改了内存地址中的值,线程1开始提交更新,发现内存地址中的值为11,而自己预期值为10,不相等提交失败,然后线程1通过自旋重新获取内存地址中的值,重新计算需要更新的值,此时,对线程1来说,A=11,B=12。

从思想上来说,CAS属于乐观锁,

二、CAS缺点

  • CPU开销较大

    • 在并发量比较高的情况下,如果许多线程通过自旋反复尝试更新某一个变量,却一直又更新不成功,会给CPU带来极大的压力
  • 不能保证代码块的原子性

    • CAS机制所保证的只是一个变量的原子性操作,而不能保证整个代码块的原子性,比如需要保证3个变量共同进行原子性的更新,就不得不使用重量级的 Synchronized 或者相应的lock
  • ABA问题

三、CAS带来的ABA问题以及解决方案

  • ABA问题产生场景
    假如内存地址中有一个值为A的变量,现在有三个线程想要更新内存地址中的值,
    线程1:获取当前值A,期望更新为B,
    线程2:获取当前值A,期望更新为B,
    线程3:期望更新为A
    接下来,线程1抢先一步执行成功,把当前值从A更新为B,同时线程2因为某种原因被阻塞了,没有进行更新操作,线程3此时过来获取到内存地址中值B,将B改为A,最后线程2恢复了运行状态,发现此时内存地址中的值和自己的期望值相等,又将值改为B。此时内存中的地址值经历了 A —> B —> A的改变。
    表面上看没有什么问题,但是在某些场景下就是致命的。
    比如,小明网上账户上有100块钱,要支付50元,由于网络等原因,多点了几下,第一次将账户的余额改为50元,此时,小红给小明转账50元,此时账户余额为100元,由于上面的网络延迟,多点几下的操作请求也遵循CAS,期望值100,更新值50,又将小明的账户余额改为50元,此时小明实际余额少了50元。
    解决方案:
    添加一个版本号,每次比较并更新版本号就能解决ABA问题。