CAS思想及应用

含义:

CAS:Compare And Set,对一个数值进行更新时,带上旧值,如果旧值与实际值相同,那么更新成功,否则,更新失败。是一种乐观锁思想。

典型实现就是JUC下的Atomic*类。

概念图:

取出来一个value,进行了加1操作(当然,可以时任何其他操作),然后将 newValue(也就是value+1)更新回去,同时带上旧的value,去硬件底层判断:如果现有值还是value,那么更新成功,如果现有值不等于value,那么更新失败。

JUC:

AtomicInteger、AtomicLong、AtomicStampedReference

以AtomicInteger来举例,来看下getAndIncrement()的源码:

this.getIntVolatile(o,offset)获取了当前的值,也就是旧值。然后在this.weakCompareAndSetInt(o,offset, v, v+delta)中进行比较并赋值:通过o和offset获取新值,然后和v进行比较,如果相同,则将v+delta赋值进去;如果不成功,则会通过this.getIntVolatile(o,offset)重新获取当前值,再次进行比较并赋值,直到成功,跳出循环。最后返回v,也就是旧值。

这就是典型的乐观锁思想,好处避免了加锁导致的线程切换,坏处是一直循环导致CPU空转。适用于:只要并发量不是特别高,在1161行和1162行执行的时间间隔内不会有另一个线程去修改这个值,那么就可以实现第一次循环中就比较并赋值成功。

ABA的问题:

CAS避免不了的一个问题就是ABA,A首先更新为了B,然后又更新为了A,在某些业务场景下,这样的情况就不能去更新这个值,应该更新失败进行重试。所以有了AtomicStampedReference:

public boolean compareAndSet(V expectedReference, V newReference, int expectedStamp, int newStamp) {
        AtomicStampedReference.Pair<V> current = this.pair;
        return expectedReference == current.reference && expectedStamp == current.stamp && (newReference == current.reference && newStamp == current.stamp || this.casPair(current, AtomicStampedReference.Pair.of(newReference, newStamp)));
    }

这个类有两个主要成员变量:reference和stamp,reference代表具体值,stamp记录了这个值对应的版本,每次reference进行修改stamp都会加1。这样即使reference从A变B再变A,由于stamp不同,比较并赋值就不会成功,从而避免ABA的问题。

应用:

Java中的CAS类,比如AtomicInteger、AtomicStampedReference等,针对的是对某个变量通过乐观锁的思想来实现这个变量本身的线程安全(所谓线程安全就是说在多线程同时对这个变量进行更新操作时,依然可以保证这个变量的值的正确性)。注意,CAS只能是实现这个变量在它所在的JVM中的线程安全,不能保证更大范围的线程安全,在实践中一般我们的应用都是多实例部署,这样这个变量并不能实现跨实例、跨JVM的线程安全。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值