JAVA 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問題
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章