【Java併發編程實戰】-----「J.U.C」:CAS操做

CAS,即Compare and Swap,中文翻譯爲「比較並交換」。java

對於JUC包中,CAS理論是實現整個java併發包的基石。從總體來看,concurrent包的實現示意圖以下:算法

201511040000·

i++是一個很是經典的操做,它幾乎充斥着咱們每一個人編寫的代碼中。咱們知道i++是能夠分解的,它分解爲getI()、i + 1 、setI三個步驟,因此它並非原子操做。若是i==1,執行兩次i++操做,咱們指望的結果是3,可是結果有可能也是2:編程

2015110500001

那麼有什麼辦法解決這個問題呢?確定有!使用鎖便可:多線程

synchronized(this){
            i++;
        }

誠然,在java中存在樂觀鎖、悲觀鎖兩種鎖。其中synchronized就是悲觀鎖,在前面咱們瞭解synchronized也是獨佔鎖,加入關鍵字synchronized的代碼通常都是以單線程的形式在運行着,它會致使其餘須要該資源的線程掛起直到前面的線程執行完畢釋放資源,因此它的效率較爲低下。而樂觀鎖則採用了一種較爲高效的方式,它的操做與synchronized不一樣,synchronized採用加鎖,而它則不採用加鎖去執行某些操做,若是發生了衝突則失敗並一直重試直到成功爲止。而CAS就是一種樂觀鎖,它所採用的策略是當且僅當預期值A和存中的值V相同,則將內存V值修改成B,不然返回V。實現以下:併發

for(;;){
            if(A==V){
                V = B;
            }
        }

固然在J.U.C中實現CAS沒有這麼簡單。this

CAS

CAS,即一種對內存中的共享數據進行操做的指令,並且該操做是原子的讀寫操做。其過程以下:首先CPU將內存中的將要被修改的數據與預期的值進行比較,若是這兩個值相等,CPU則會將內存中數值替換爲新值,不然不作操做。最後,CPU會將舊值返回。在java中,CAS的含義就是「我認爲的本來的值是什麼,若是你是,則更換爲新值,不然不作修改同時麻煩告訴我該值時多少」spa

在CAS中,總共存在三個操做數:預期值A、內存中的V、修改的值B。當且僅當預期值A和內存中的值V相同,則將內存V值修改成B,不然返回V。使用這種機制編寫的算法也叫做非阻塞算法,標準定義了一個線程的失敗或者掛起是不會影響其餘線程的失敗或者掛起。.net

下面咱們來已AtomicIneger的源碼爲例來看看CAS操做:線程

public final int getAndAdd(int delta) {
        for (;;) {
            int current = get();
            int next = current + delta;
            if (compareAndSet(current, next))
                return current;
        }
    }

這裏很顯然使用CAS操做(for(;;)裏面),他每次都從內存中讀取數據,+1操做,而後兩個值進行CAS操做。若是成功則返回,不然失敗重試,直到修改爲功爲止。翻譯

上面源碼最關鍵的地方有兩個,一個for循環,它表明着一種寧死不屈的精神,不成功誓不罷休。還有就是compareAndSet:

public final boolean compareAndSet(int expect, int update) {
    return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
    }

CAS的缺陷

儘管CAS機制可使咱們不依賴與同步,不影響和掛起其餘線程,它大大提高了運行的效率,可是它會致使一個ABA的問題,以下:加入有兩個線程A、B,他們都讀取內存中的數據V,假如這個時候線程A,先將V修改成V1,而後又修改成V,這個時候線程B的compareAndSet仍然能成功,對於線程B而言該值V並無發生任何變化,而實際上它已經變化了,只不過最後又還原了而已。

 

參考文獻

一、Java的多線程編程模型5--Java中的CAS理論

二、JAVA CAS原理深度分析

相關文章
相關標籤/搜索