CAS深度剖析(CAS你都懂了么)

目录

一、前言

二、使用

1、什么场景下使用CAS

2、如何使用CAS

三、原理

1、CAS的底层实现

2、AtomicInteger的getAndAdd在1.7的实现

3、AtomicInteger的getAndAdd在1.8的实现

四、问题

1、ABA问题

2、ABA带来的问题

3、如何解决ABA问题

a、业务实现

b、版本号

五、惯例


一、前言

CAS想必大家都很熟悉,稍微看过源码的同学都会麻烦在哪里都能够看到CAS的身影,那么到底应该怎么使用CAS,是不是什么场景下都可以使用,使用CAS会存在什么问题?关于CAS有太多太多的问题,我们今天就和同学们一起聊聊关于CAS的话题。

 

二、使用

1、什么场景下使用CAS

我想大家都知道在需要更新一个共享资源,此时想通过自旋等待的方式来防止加锁导致频繁的上线文切换,从而提高效率。

那么是不是这种场景就一定适合使用CAS呢?答案当然是否定的。使用CAS会带来一定的CPU消耗,或者说是浪费。我们考虑这样一个场景,统一需要更新一个共享资源,但是这个资源的更新竞争非常大,在这个场景下其实我们就不适合使用CAS自旋的方式了,而是要采取加锁的方式。因为竞争大会导致更多的CPU时钟被自旋浪费,从而导致CPU使用高,且更新资源的速度也不快。而此时如果直接采用加锁的场景,则可以大大减少CPU的使用,且能够提高资源的更新速度。

因此CAS自旋的方式,其实只适合需要更新共享资源,且资源的更新竞争不大的场景。

2、如何使用CAS

具体如何使用CAS本文就不具体介绍了,常用的方式也是就CAS自旋实现吧。

三、原理

1、CAS的底层实现

CAS的实现就调用了UnSafe方法中的compareAndSwap***的系列native方法。

这些nativie方法其实在底层都是通过CPU指令实现的,因此CAS操作本身是很快的,这也是为什么CAS自旋的方式想必加锁能够提高性能的原因。

2、AtomicInteger的getAndAdd在1.7的实现

在1.7中,AtomicInteger.getAndAdd其实就是使用的常规的CAS自旋的方式实现的。

3、AtomicInteger的getAndAdd在1.8的实现

在1.8中,AtomicInteger.getAndAdd的实现确实直接调用了Unsafe类中的getAndAdd方法实现,但是我们进入Unsafe方法,你却会发现其实现也是使用了CAS的自旋方式。

为什么1.8的CAS自旋要移动到Usafe类中呢?其实这里有个优化。因为现在有些现代CPU已经能够支持getAndAdd指令了,因此就可以直接将这个方法使用CPU指令实现,而不再需要使用原来的CAS自旋的方式实现。但是毕竟不是所有的CPU都支持这个指令,因此JDK就将getAddAdd的方法写到了UnSafe类中,并在底层对其进行特殊处理。如果底层CPU支持getAndAdd的指令则直接调用底层指令实现该功能,如果底层CPU指令不只会该指令,则直接执行Unsafe中对应的方法(CAS自旋的方式)来实现该功能。

 

四、问题

1、ABA问题

想必大家都听说过CAS带来的ABA问题。因为CAS是通过比较旧值再设置新值的操作。如果有如下场景,假设我们需要有线程A需要执行如下指令:当a=4的时候将a设置为5。那么CAS能够确保指令的正确执行,却不能保证期间没有其他指令执行过。比如在其过程中很有可能某线程将a改成了5,然后又有另外的线程将a改成了4。那么对于线程A来说,a仍然等于4,于是他完全感知不到另外两个线程执行过,这就是ABA问题。

2、ABA带来的问题

其实在我们普通的更新操作中,ABA问题本身并不会给我的程序带来什么问题或者一次,因此我们并不需要关心它。

但是如果我们需要确保自己的线程在执行CAS指令期间,不能其他线程也执行成功,那么就需要处理ABA的问题了。

3、如何解决ABA问题

a、业务实现

这个方式最简单,就是业务上要求需要修改的变量只能够越来越多,不能变小。这样就可以从业务上确保ABA问题不会存在。

b、版本号

这个方法就是每次在对变量修改的时候都更新一下版本号,这样每次判断的时候还需要对版本号进行对比,这样就可以解决ABA问题。其实这和我们上面提到的业务实现是类似的思想。只是使用这种防范我们可以使用官方提供的方法实现:AtomicStampedReference.具体如何使用本文就不详细介绍了。

五、惯例

如果你对本文有任何疑问或者高见,欢迎添加公众号共同交流探讨(添加公众号可以获得”Java高级架构“上10G的视频和图文资料哦)。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值