CAS 详解

CAS

CAS是指Compare And Swap比较并交换,是一种很重要的同步思想。如果主内存的值跟期望值一样,那么就进行修改,否则一直重试,直到一致为止。

public class CASDemo {
    public static void main(String[] args) {
        AtomicInteger atomicInteger=new AtomicInteger(5);
        System.out.println(atomicInteger.compareAndSet(5, 2019)+"\t current data : "+ atomicInteger.get());
        //修改失败
        System.out.println(atomicInteger.compareAndSet(5, 1024)+"\t current data : "+ atomicInteger.get());
    }
}

第一次修改,期望值为5,主内存也为5,修改成功,为2019。第二次修改,期望值为5,主内存为2019,修改失败。

查看AtomicInteger.getAndIncrement()方法,发现其没有加synchronized也实现了同步。这是为什么?

CAS底层原理

AtomicInteger内部维护了volatile int valueprivate static final Unsafe unsafe两个比较重要的参数。

public final int getAndIncrement(){
    return unsafe.getAndAddInt(this,valueOffset,1);
}

AtomicInteger.getAndIncrement()调用了Unsafe.getAndAddInt()方法。Unsafe类的大部分方法都是native的,用来像C语言一样从底层操作内存。

public final int getAnddAddInt(Object var1,long var2,int var4){
    int var5;
    do{
        var5 = this.getIntVolatile(var1, var2);
    } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));
    return var5;
}

这个方法的var1和var2,就是根据对象偏移量得到在主内存的快照值var5。然后compareAndSwapInt方法通过var1和var2得到当前主内存的实际值。如果这个实际值快照值相等,那么就更新主内存的值为var5+var4。如果不等,那么就一直循环,一直获取快照,一直对比,直到实际值和快照值相等为止。

比如有A、B两个线程,一开始都从主内存中拷贝了原值为3,A线程执行到var5=this.getIntVolatile,即var5=3。此时A线程挂起,B修改原值为4,B线程执行完毕,由于加了volatile,所以这个修改是立即可见的。A线程被唤醒,执行this.compareAndSwapInt()方法,发现这个时候主内存的值不等于快照值3,所以继续循环,重新从主内存获取。

CAS缺点

CAS实际上是一种自旋锁,

  1. 一直循环,开销比较大。
  2. 只能保证一个变量的原子操作,多个变量依然要加锁。
  3. 引出了ABA问题

猜你喜欢

转载自blog.csdn.net/luweibin19/article/details/106157842