CAS原理分析,解決銀行轉(zhuǎn)賬ABA難題
時間:2021-10-11 13:44:12
手機看文章
掃描二維碼
隨時隨地手機看文章
[導(dǎo)讀]來源:https://ddnd.cn/2019/03/13/java-cas/?什么是CASCAS即CompareAndSwap的縮寫,翻譯成中文就是比較并交換,其作用是讓CPU比較內(nèi)存中某個值是否和預(yù)期的值相同,如果相同則將這個值更新為新值,不相同則不做更新,也就是CAS是原子...
什么是CAS
Unsafe源碼分析
Unsafe有很多個CAS操作的相關(guān)方法,這里舉例幾個
public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5);
public final native boolean compareAndSwapLong(Object var1, long var2, long var4, long var6);

-
將對象引用、值在對象中的偏移量、期望的值和欲更新的新值傳遞給Unsafe.cpp
-
如果值更新成功則返回true給開發(fā)者,沒有更新則返回false
-
接受從Unsafe傳遞過來的對象引用、偏移量、期望的值和欲更新的新值,根據(jù)對象引用和偏移量計算出值的地址,然后將值的地址、期望的值、欲更新的新值傳遞給CPU
-
如果值更新成功則返回true給Unsafe.java,沒有更新則返回false
-
接受從Unsafe.cpp傳遞過來的地址、期望的值和欲更新的新值,執(zhí)行指令cmpxchg,比較地址中的值是否和期望的值一樣,一樣則將值更新為新的值,不一樣則不做任何操作
-
將操作結(jié)果返回給Unsafe.cpp
CAS的缺點
ABA問題
-
線程1,期望值為A,欲更新的值為B
-
線程2,期望值為A,欲更新的值為B
小明在提款機,提取了50元,因為提款機問題,有兩個線程,同時把余額從100變?yōu)?0
線程1(提款機):獲取當前值100,期望更新為50,
線程2(提款機):獲取當前值100,期望更新為50,
線程1成功執(zhí)行,線程2某種原因block了,這時,某人給小明匯款50
線程3(默認):獲取當前值50,期望更新為100,
這時候線程3成功執(zhí)行,余額變?yōu)?00,
線程2從Block中恢復(fù),獲取到的也是100,compare之后,繼續(xù)更新余額為50?。?!
此時可以看到,實際余額應(yīng)該為100(100-50 50),但是實際上變?yōu)榱?0(100-50 50-50)這就是ABA問題帶來的成功提交。
循環(huán)時間長開銷大
這種循環(huán)也稱為自旋
只能保證一個共享變量的原子操作
CAS的應(yīng)用
-
樂觀鎖總是假設(shè)最好的情況,每次去操作數(shù)據(jù)都認為不會被別的線程修改數(shù)據(jù),所以在每次操作數(shù)據(jù)的時候都不會給數(shù)據(jù)加鎖,即在線程對數(shù)據(jù)進行操作的時候,別的線程不會阻塞仍然可以對數(shù)據(jù)進行操作,只有在需要更新數(shù)據(jù)的時候才會去判斷數(shù)據(jù)是否被別的線程修改過,如果數(shù)據(jù)被修改過則會拒絕操作并且返回錯誤信息給用戶。
-
悲觀鎖總是假設(shè)最壞的情況,每次去操作數(shù)據(jù)時候都認為會被的線程修改數(shù)據(jù),所以在每次操作數(shù)據(jù)的時候都會給數(shù)據(jù)加鎖,讓別的線程無法操作這個數(shù)據(jù),別的線程會一直阻塞直到獲取到這個數(shù)據(jù)的鎖。這樣的話就會影響效率,比如當有個線程發(fā)生一個很耗時的操作的時候,別的線程只是想獲取這個數(shù)據(jù)的值而已都要等待很久。