目录
一、什么是CAS
CAS是 compare and swap 的缩写,意为“比较和交换”。本身并不是锁,却可以实现锁的功能,是一种无锁式并发编程技术。乐观锁。
他的具体过程(用自增1为例):
步骤一:获取 i 值存在对象E中(E = i);
步骤二:对E进行自增,自增后为V;
步骤三:重新获取i值和E比较,如果相同,就把i改成V;如果不相同继续读取 i 值重复步骤一二三操作,知道修改成功。
源码如下:
AtomicInteger i = new AtomicInteger();
i.incrementAndGet();
查看incrementAndGet()方法:
public final int incrementAndGet() {
return unsafe.getAndAddInt(this, valueOffset, 1) + 1;
}
查看getAndAddInt()方法:
public final int getAndAddInt(Object var1, long var2, int var4) {
int var5;
do {
var5 = this.getIntVolatile(var1, var2);
} while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));
return var5;
}
在这里使用了一个方法“compareAndSwapInt” 他的底层是由汇编语言实现的,其实现的逻辑就是比较和改变;
而在汇编语言使用的是:lock cmpxchg //防止在比较和修改两个操作之间有别的操作插入,对这个命令进行加锁。 cmpxchg == cas
二、ABA问题
ABA问题是什么:在步骤三时,有线程进来修改后又被别的线程修改回来了,虽然此时 i 和
E相同,但是其中并不是原子性了(别的线程抢占资源了);
解决ABA问题:对修改的值添加一个版本号(每次修改后对版本号加1),步骤三比较的时候,不仅要比较值还要比较版本号。
三、长时间自旋问题
CAS 多与自旋结合。如果自旋 CAS 长时间不成功,会占用大量的 CPU 资源。
解决方法是:如果长时间自选失败,就让线程挂起。
四、多共享资源时保证原子性
CAS是针对一个共享资源可以保证原子性,对于多个共享资源如何解决:将多个共享资源放在一个对象里,使用AtomicReference关键字保证对象的原子性。