理解
CAS的全称是compare And Swap意思就是比较再交换,它一种特殊的CPU指令,可以完成比较和交换的这一系列不可中断的组合操作,由CPU保证了它的原子性。cas主要就是在数据在发生修改动作的前一刻获取内存值与预期的值进行比较,如果不等于预期的值就不进行修改,如果和预期的值相等则进行修改,cas在进行比较时如何失败了会采取相应的措施,比如重试、报错等。cas的三个要素是内存值A,预期值B,修改后的值C,如果A等于B,则将B修改为C,如果不相等就不修改转而进行失败的措施
CAS主要的几个类例如:atomic包下的AtomicInteger等都是使用了CAS保证了他们的并发安全性
![](https://img.haomeiwen.com/i22844171/37cfee39f2e1c6a9.png)
CAS主要是由NATIVE的方法unsafe实现的,我可以随便点开一个AtomicInteger看看其源码
public class AtomicInteger extends Number implements java.io.Serializable {
private static final long serialVersionUID = 6214790243416807050L;
private static final Unsafe unsafe = Unsafe.getUnsafe();
private static final long valueOffset;
//这个是Atomic比较核心的地方,主要就是获取AtomicInteger类value这个这个字段在地址的偏
//移量,也就是地址,这个value字段是使用的volatile 进行修饰的,保证了字段的可见性
static {
try {
//获取此方法中value值的内存偏移量
valueOffset = unsafe.objectFieldOffset
(AtomicInteger.class.getDeclaredField("value"));
} catch (Exception ex) { throw new Error(ex); }
}
//value主要是保存了类中的需要操作的数据,
private volatile int value;
//AtomicInteger初始化就是对value进行赋值
public AtomicInteger(int initialValue) {
value = initialValue;
}
在看看这个对数据操作的方法如何保证数据的并发安全的,我们随便点开一个对数据修改的方法getAndAdd方法
//我们可以看到,其实对数据操作的是unsafe的类的getAndAddInt方法
public final int getAndAdd(int delta) {
return unsafe.getAndAddInt(this, valueOffset, delta);
}
接下来点到unsafe.getAndAddInt内部去看看
//这里主要是通过getIntVolatile方法通过内存偏移量获取对象最新的值,
//然后调用cas方法,如果失败了就不断的重试获取对象新值然后CAS,直到cas成功为止
public final int getAndAddInt(Object var1, long var2, int var4) {
int var5;
do {
//先去内存中获取内存地址所指向的值,这个将这个内存值赋值给var5,这个方法是native方法
//var5代表着偏移量指向的底层内存的值,
//var5将是我们所谓的预期值
var5 = this.getIntVolatile(var1, var2);
//在将要进行修改时先检查一次内存的值还是否是预期值var5,将偏移量var2、对应的unsafe对象var1
//和var5带进compareAndSwapInt去获取此时内存中偏移量所指向的数值然后
//和预期值var5进行比较,如果是相等的就将偏移量var2指向的主内存地址中的值修改为
//var5 + var4,失败就进行重试,每次重试都会去内存中重新获取值赋值给var5,然后修改时再比较一下,
//这个方法是native方法,这个也乐观锁的体现
} while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));
return var5;
}
cas相对于同步锁的优点就在于如果在并发量不是很高时cas机制会提高效率,但是在竞争激烈并发量大的情况下效率是非常低下的,原因在于自旋时间过长,失败次数过多造成重试次数过多
网友评论