1. 程式人生 > 實用技巧 >java基礎----CAS

java基礎----CAS

一.什麼是cas

  CAS的全稱是Compare-And-Swap,他是一條CPU併發原語。

  java中的CAS,都是通過unsafe類實現的,其主要的操作是,當一個執行緒從主記憶體拿到一個變數到自己工作記憶體,並經過計算處理,準備寫回主記憶體的時候,會首先比對當前主記憶體的變數指向的記憶體地址裡面的值,與期望值(執行緒一開始拿變數時,變數對應的值)是否相等,如果相等,則表示沒有其他執行緒對這個變數操作過,隨後就將要更新的值寫進主記憶體中。假如不相等,則表示有執行緒修改過這個變數,則會把主記憶體中變數的最新值拿回去,重新做一次計算操作,以此迴圈。

二.cas的底層原理

下面是java atomicInteger的程式碼:

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

下面是unsafe.class中的程式碼(這個類是java的原生類,在jdk的rt.jar/sun/misc裡面):

//第一個引數var1為給定物件,var2為物件記憶體的偏移量,通過這個偏移量迅速定位欄位並設定或獲取該欄位的值,
//var5表示期望值,var4表示要新增的數值
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;
}

可以看出,unsafe類可以直接操作指標,根據給定的物件和記憶體偏移量迅速地獲取到變數值。在do...while中,首先根據物件和記憶體偏移量拿到一個值作為期望值,然後在while的條件語句中,再一次根據物件和記憶體偏移量獲取變數的當前值,並與期望值作出對比,如果相等,則加上var4。假如不相等,則從新獲得期望值,並迴圈。

三.CAS的缺點

  最明顯的一點,CAS有可能出現一個很長的迴圈,假如執行緒一直沒有寫成功,那他就會一直自旋,非常消耗CPU資源。而且它只能保證一個共享變數的操作,對於多變數操作,只能加鎖。

  其次就是ABA問題,導致ABA問題的原因是兩個執行緒的工作時間差距太大。例如執行緒a需要10秒,執行緒b需要2秒,它們同時從主執行緒中拿到x1並開始工作,在10秒中,執行緒b先把x1改成x2,x2改成x3。。。。最後x3又該回去x1,這時候執行緒a算出結果x4並對主記憶體中的變數進行CAS操作,通過比較期望值和現時變數的值發現是一致的,就認為這段時間裡面沒有其他執行緒對變數進行修改過,但是實際上,這個變數以及是被修改過多次了。