一、概念
CAS—compareAndSet字面意思:比较并交互
真实值和期望值相同,执行修改,否则不执行。
CAS方法存在于UnSafe类中,UnSafe可以直接操作系统内存资源。
CAS是一种系统原语,属于操作系统用语,是有若干条连续,不可中断的指令构成的,也就是说,CAS是一条CPU的原子指令。
二、源码阅读示例
我们以UnSafe的getAndSetInt方法为例
这个方法的作用是,获得并且设置一个int值,返回获得的结果
public final int getAndSetInt(Object var1, long var2, int var4) {
int var5;
do {
var5 = this.getIntVolatile(var1, var2);
} while(!this.compareAndSwapInt(var1, var2, var5, var4));
return var5;
}
首先这个方法接收4个参数,第一个为对象,第二个是内存地址偏移量,我们通过这两个参数,直接从内存中获得我们需要的操作数var5
while里的判断条件,就是一个本地的CAS方法,比较并交换int值
public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5);
这是个返回boolean的方法,意思是:如果期望值和实际值相等,则交换,返回true,否则返回false。这个方法以在cpu级别保证了原子性,不会发生数据不一致问题。
再回到上面的循环,如果CAS交换成功,返回true,那么循环条件整体为false,退出循环,返回更新之前的操作数,如果CAS交换失败,那么则会一直重复这个do-while循环,不停的取值,尝试比较并交换。我们把它称之为自旋
三、ABA问题和原子引用
ABA故名思意,A变成了B又变成了A,从结果上看,A并没有改变,但实际上是A改变了多次。
以CAS的机制是不能意识到变量是改变了多次的。
JUC提供了AtomicStampedReference,即带戳的原子引用类,可以理解为有版本号的原子引用
AtomicStampedReference<Integer> asr = new AtomicStampedReference<>(100,1)
通过版本号,解决ABA的问题,这样引用和预期相同,版本号却和预期不相通,不能执行CAS操作
boolean res = asr.compareAndSet(exceptref, newref,exceptstamp,newstamp);
四、小总结
CAS是CPU级别的原子指令,保证了数据一致性
CAS提升了并发效率,也增大了CPU开销(因为一直自旋的原因)
CAS只能保证一个共享变量的原子性
CAS存在ABA的问题,可以使用AtomicStampedReference类来解决。