CAS是什么?彻底搞懂CAS

CAS(Compare-And-Swap),它是一条CPU并发原语,用于判断内存中某个位置的值是否为预期值,如果是则更改为新的值,这个过程是原子的。

CAS基本原理
CAS并发原语体现在Java中就是sun.misc.Unsafe类中的各个方法。调用UnSafe类中的CAS方法,JVM会帮我们实现CAS汇编指令。这是一套完全依赖于硬件的功能,通过它实现了原子操作。由于CAS是一种系统原语,原语属于操作系统用语,原语由若干指令组成,用于完成某个功能的一个过程,并且原语的执行必须是连续的,在执行过程中不允许被终端,也就是说CAS是一条CPU的原子指令,不会造成所谓的数据不一致的问题

unsafe类分析

如下是Unsafe类中的compareAndSwapInt,是一个本地方法,在unsafe.cpp中
在这里插入图片描述

CAS具体应用
V;内存中地址存放的实际值

O:预期值(旧值)

N:新值,表示我们准备更新V的值

当执行CAS后,如果V == O ,即旧值与内存中实际值相等,表示上次修改后没有任何线程再次修改此值,因此可以将N替换到内存中。

如果 V != O,表示该内存中的值已经被其他线程做了修改,所以无法将N替换,返回最新的值V

当多个线程使用CAS操作一个变量时,只有一个线程会成功,并成功更新变量值,其他线程均会失败。失败线程会重新尝试或将线程挂起(阻塞)

CAS实现原子操作三大问题

CAS的ABA问题

CAS算法实现的一个重要前提需要取出内存中某时刻的数据并在当下时刻比较并替换,那么在这个时间差类会导致数据的变化,比如线程M从内存位置W取出值A,这时N也取出A,N操作后A变成了B,然后N将B又变回A,这时线程M在CAS操作时发现内存中仍然是A,然后M执行成功,M虽然执行成功,但实际上就出现了ABA问题。

解决方案:Java1.5开始,JDK的Atomic包里提供了一个类AtomicStampedRefernce来解决ABA问题。这个类的compareAndSet方法的作用是首先检查当前引用是否等于预期引用,并且检查标志stamped是否为预期标志,如果全部一致,则继续。

CAS的循环时间长开销大问题

自旋CAS如果长时间不成功,会给CPU带来非常大的执行开销,如果JVM能支持处理器提供的pause指令,那么效率会有一定的提升

pause指令的两个作用:

第一,它可以延迟流水线执行指令,使CPU不会消耗过多的执行资源

第二,它可以避免在退出循环的时候因内存顺序冲突而引起CPU流水线被清空

CAS的只能保证一个共享变量的原子操作问题

当对一个共享变量进行原子操作,循环CAS可以解决,但是如果是多个共享变量呢?循环CAS无法解决这个问题。

取巧的话就是合并共享变量:i=2,j=a -> ij=2a; 如此合并就可以操作了

解决方案:Java 5 开始,JDK提供了AtomicReference类来保证引用对象之间的原子性,就可以把多个变量放在一个对象进行CAS操作

猜你喜欢

转载自blog.csdn.net/yujing1314/article/details/105943128
Cas