1. 程式人生 > >Java多執行緒: CAS

Java多執行緒: CAS

悲觀鎖與樂觀鎖

悲觀鎖:悲觀鎖思想認為如果多個執行緒中使用共享資源,則它們肯定會同時進行修改從而引起衝突,悲觀鎖的解決方式是共享資源每次只給一個執行緒使用,其它執行緒阻塞,用完後再把資源轉讓給其它執行緒。synchronized和ReentrantLock等獨佔鎖就是悲觀鎖思想的實現。

樂觀鎖:樂觀鎖思想認為如果多個執行緒使用共享資源,它們修改應該是有先後順序的,不會同時進行修改,如果真的有衝突則後面修改失敗。樂觀鎖的解決方式是共享資源可以由多個執行緒同時訪問修改,對於衝突失敗,讓其重試直到成功即可。

什麼是CAS

CAS全程是compareAndSwap,維基百科上的中文稱為“比較並交換”,是樂觀鎖的一種實現方式,涉及有三個運算元,記憶體位置(V)、預期值(A)和新值(B),如語句CAS(V,A,B),當*V等於A時,則將值替換為新值B。雖然從語言描述上來說是分為多個操作的,但實際上CAS操作是一個原子操作,是基於CPU提供的原子操作指令實現的。如下CAS實現更新的虛擬碼:

 do {
        A=current();//*V賦予A,A為就是預期值

        B=update();//獲取B作為新值

    } while(!compareAndSwap(V, A, B));

*V:使用了C語言描述,表示V記憶體位置的值,便於描述
更新:我們所說的更新是指更新記憶體位置V的值,也就是改變*V

上面虛擬碼將*V賦予A,然後獲取新值賦予B,最後進行交換判斷直到成功,例如:

- 1 2 3 4 5 6
執行緒1 A=5 B=6 CAS:false
執行緒2 A=5 B=7 *V=7

上面兩個執行緒同時進入迴圈進行進行更新操作,第一輪迴圈中只有執行緒2更新成功,執行緒1因為*V的值被執行緒2改變導致和預期值不一致從而失敗,只能重新進入下一輪迴圈直到成功。

CAS解決了什麼問題

其實這個問題前面介紹悲觀鎖和樂觀鎖時其實已經回答,當多個執行緒操作時,它解決了悲觀鎖使用了獨佔鎖,一次只能有一個執行緒進入臨界區的問題,在競爭狀態比較低的情況下提高了併發效能。為何說是競爭低的情況下,如果上面有很多個執行緒同時進入迴圈,那麼每個執行緒都在佔用資源執行,但每次只有一個執行緒能更新成功。

CAS缺點

1.當競爭很強烈時,每個執行緒都佔用資源執行但是隻有一個成功

2.ABA問題,上面的例子中,如果還有一個執行緒3在修改,並將執行緒2修改後的值又變成了5,那麼執行緒1此時是察覺不到的,它還能進行成功的執行!例如:

- 1 2 3 4 5 6 7 8 9
執行緒1 A=5 B=6 *A=6
執行緒2 A=5 B=7 *V=7
執行緒3 A=7 B=5 *A=5

ABA問題解決方式:引入一個版本號,在每次更新後都加1,在上面的例子中,即時執行緒3將*V修改回來原值,因為版本號不一致也會導致失敗重試。

CAS在java.util.concurrent有著廣泛的使用,如AtomicInteger。且對於ABA問題,Java也提供了AtomicStampedReference來處理。