美文网首页
并发编程之CAS

并发编程之CAS

作者: 林千景 | 来源:发表于2019-02-15 02:22 被阅读0次

写在前面

上一篇我们分析了volatile变量对于内存可见性的保证以及抑制指令重排的特性,了解到在多线程对volatile变量的读写不会发生线程阻塞,但是volatile变量只能保证可见性和有序性,并不能保证原子性,即i++之后的数据仍然是不正确的。目前保证原子性的方式只有加锁,无论是内置锁(synchronized),还是显示锁(ReentrantLock),加锁意味着线程阻塞,如果竞争激烈,很可能导致频繁的线程上下文切换,从而大大降低了性能。鉴于此,我们希望有一种机制,既可以保证原子性,又能够使得线程不发生阻塞,幸运的是,java的先行者已经为我们做好了这些,这就是今天的主角——CAS。

CAS分析

CAS,即compare and swap,比较更新机制。它涉及到三个参数,内存值V,旧值A,新值B。当且仅当V=A时,我们才去将变量的值更新成B并返回true,否则返回false。(这个比较再更新的原子性是由操作系统底层来实现的,我们并不需要关心)

JUC下的atomic类都是通过CAS来实现的,我们以AtomicInteger为例来说明。

AtomicInteger i = new AtomicInteger(0);
i.increasementAndGet();
01.png

如图所示,我们开启了三个线程并发对AtomicInteger类型的变量i进行increasementAndGet的自增操作,i的值初始化为0,首先,每个线程都会先去读取i的值,然后进行院子的CAS操作,在CAS操作里,如果此时i的值还是之前读到的值,则更新为新值;如果CAS操作里i的值不少刚刚获取的值,说明有其他线程先于本线程修改了i,CAS失败,失败之后自旋,再次读取i的值,再次CAS操作。

对应于上图,我们假设线程1先于线程2,3执行,线程2,3同时执行,完整的流程就是:

  • 线程1首先拿到变量id值为0,此时就它一个线程,直接进行CAS操作,将0改成1
  • 线程2,线程3同时读取到变量id值为1,假设线程2抢先一步发起CAS操作,在CAS操作里,它会检查此时变量i的值是否还是1,如果是,则更新为2。
  • 线程3发起CAS操作,它去检查变量i的值,发现不是1而是2,CAS失败。然后进入自旋,再次读取变量i的值为2,紧接着进入CAS操作,检查变量i是否还是2,此时是2,则更新为3。

上述过程,就是Atomic原子类的实现原理,并没有基于加锁串行化处理,通过CAS方式,无锁地进行更新,而CAS是由操作系统底层保证了其操作的原子性。

CAS实现原子操作的三大问题

  1. ABA问题
    CAS操作需要检查当前内存的变量值是否和刚刚读取的值相同,假设一个变量是A,变成了B,之后又变成了A,所以在进行CAS操作的时候检查到它的值没有发生变化。ABA的解决方案就是加上版本号1A->2B->3A,类似这种。java先行者们也给我们提供了AtomicStampedReference来解决ABA的问题,其中的预期标志也类似于版本号的功能。
  2. 循环时间长开销大
    多线程竞争激烈的情况下进行CAS操作,会导致某些线程长时间空循环,也就是说它什么都没做,只是不停地在浪费处理器的处理时间而已。
  3. 只能保证一个共享变量的原子操作
    一个共享变量的操作可以用CAS保证其原子性,多个共享变量的操作,循环CAS是无法保证其原子性的。有个取巧的办法,java先行者设计的AtomicReference类,我们可以通过将多个变量放到一个对象里面,然后由AtomicReference进行原子性地更新。

参考文档

方腾飞《并发编程的艺术》

相关文章

  • 并发编程之CAS

    写在前面 上一篇我们分析了volatile变量对于内存可见性的保证以及抑制指令重排的特性,了解到在多线程对vola...

  • Java并发编程之CAS

    CAS(Compare and swap)比较和替换是设计并发算法时用到的一种技术。简单来说,比较和替换是使用一个...

  • Java并发编程之CAS

    转载:http://ifeve.com/compare-and-swap/ CAS(Compare and swa...

  • 并发编程之CAS(二)

    更多Android架构进阶视频学习请点击:https://space.bilibili.com/474380680...

  • Java并发编程之CAS

    在Java并发编程的世界里,synchronized 和 Lock 是控制多线程并发环境下对共享资源同步访问的两大...

  • (五)深入剖析并发之AQS独占锁&重入锁(ReetrantLoc

    引言 在我们前面的文章《深入理解Java并发编程之无锁CAS机制[https://www.jianshu.com/...

  • 并发编程之 CAS 的原理

    前言 在并发编程中,锁是消耗性能的操作,同一时间只能有一个线程进入同步块修改变量的值,比如下面的代码 如果不加 s...

  • Java并发编程之CAS原理

    什么是CAS? CAS:Compare and Swap,即比较再交换。CAS有3个操作数:① 内存值V;② 旧的...

  • CAS乐观锁

    什么是CAS CAS比较并替换,是一种并发编程中用到的一种技术。 CAS是原子性,保证并发安全,而不是保证并发同步...

  • Java并发编程之Java CAS操作

    该文章属于《Java并发编程》系列文章,如果想了解更多,请点击《Java并发编程之总目录》 前言 在上一篇文章中我...

网友评论

      本文标题:并发编程之CAS

      本文链接:https://www.haomeiwen.com/subject/fgmueqtx.html