CAS無鎖演算法介紹

Java中的鎖大家都很熟悉,在面對高併發的情況下,會使用鎖去實現執行緒安全。例如synchronized關鍵字、Concurrent包中的Lock物件,今天給大家介紹一個CAS演算法,看一下CAS演算法怎麼實現執行緒安全。

所謂CAS(compare and Swap)演算法,即比較和交換,這麼講可能比較抽象,透過下面這張圖會更好理解一點。

CAS無鎖演算法介紹

CAS演算法示意圖

橙色和藍色表示兩個執行緒,兩個執行緒都想修改i的值。首先兩個執行緒先去資料庫(假設i存放在資料庫中)中撈一下i的值,並把i的值儲存在本地,比如圖中的變數A,然後執行自己執行緒的程式碼,比如i++。我們假設橙色執行緒先執行完程式碼,那麼i的值變成了4儲存在本地即變數B(注意,此時資料庫中i的值還是3),這時候橙色執行緒再去資料庫撈一下i的值,和本地存的值A做對比,如果是一樣都是3,那麼就會把資料庫中i的值更新成4。

橙色執行緒執行完畢之後,藍色執行緒也會執行自己執行緒的程式碼,比如i++,執行完之後把值儲存在變數B中,然後也去資料庫撈一下i的值,但是此時i的值變成了4和本地存的值A=3不一樣,就會更新本地A的值,然後再執行一遍執行緒程式碼(i++),執行完畢B=5,然後再去撈一下資料庫中i的值和本地A儲存的值對比,一致則把資料庫中i的值更新完畢,不一致則繼續迴圈。

CAS核心就是比較和交換,正如圖片中所說,我認為V的值應該是A,是就執行更新操作,不是則更新V的值,然後再執行一遍執行緒的程式碼。

但是CAS演算法也存在一些弊端,比如經典的ABA的問題,比如說圖中橙色執行緒把i更新成了4之後,又有另外一個執行緒把i的值又變成了3,然後藍色執行緒再去執行的時候,雖然i的值對藍色執行緒來說是3沒變過,但是其實不是當時藍色執行緒取的那3,已經變過了。這種弊端可以用加標籤的方式去解決,比如加上時間戳。還有一個弊端就是當執行緒很多時,所有執行緒都在改變同一個變數的值比如圖中的i,那麼意味著大部分的執行緒一直在比較和交換,因為i的值一直在變,這樣就很消耗系統的效能,因此這種情況可能使用其他鎖更為合適。