CAS(樂觀鎖)與ABA問題
cas是什麼
CAS 全稱 compare and swap 或者compare and exchange 比較並且交換。用於在沒有鎖的情況下,多個執行緒對同一個值的更新。
cas原理
例如,我們對一個int i進行遞增操作。原來,為了執行緒安全,需要在遞增程式碼上加一把鎖 sync 。CAS的實現方式為:不去加鎖,讀取當前的值,將原值存入E中,然後計算,得到計算結果1,這個時候的新值存入V中。然後調用一個比較並交換的方法(底層彙編指令) 這個方法的作用是:如果E和現在的i值相等,說明沒有地方對原值進行過操作。那麼就將i的值替換為V的值。
如果有別的執行緒對i進行操作了(例如:i被修改為了2),那麼將i的新值讀取,然後再進行一次計算操作(將i=2 作為最初值,進行計算,得到結果3 )。然後再次調用比較並交換的方法,去進行值的更新操作。一直循環,直到更新成功(有的鎖在更新到一定次數後,會進行鎖升級,但是這個跟CAS沒關係)
CAS底層原理
cas追程式碼的時候,可以追到native部分,但是,這裡面提供的都是一些介面,但是沒有具體的底層實現。具體的實現,需要看虛擬機的實現。
jvm的底層實現分為不同的公司的不同實現:Oracle的為hotSpot實現,這個是最常見的。我們可以看到程式碼的開源版本是openjdk。比如阿里的taobaoVM 。Ibm 的J9等。
在openjdk 中,unsafe類在實現CompareAndSwapInt 方法時,是調用的Atomic類的cmpxchg方法,然後一通方法調用,最終調用到彙編語言的 lock_if_mp(lock if multi processors 如果是多個cpu 那麼會鎖定) cmpxchg 這兩個 指令 ,最終執行 lock cmpxchg 指令
這裡的lock是一一個鎖定北橋晶片的鎖,用於解決當前cpu在進行比較和修改的時候的其他cpu對該值進行操作的問題。保證執行緒安全。
aba問題
在執行緒A進來時,讀取到的值為1。在A進行計算的時候執行緒B取到了i的值,然後更新為了2。然後執行緒C又取到i=2的值,進行C的計算後,然後得到結果為1 又將i的值修改為了1 這個時候,執行緒A進行判斷的時候,會認為在其計算過程中沒有其他執行緒對i進行過操作。ABA有的會產生影響,有的不會,如果沒有影響,不需要考慮該問題。
aba問題解決
解決方法:加上版本號,每個執行緒讀取完,賦值的時候,修改版本號,比較的時候,對比i值+版本號。