CAS下ABA問題及優化方案

2022-02-15 21:55:52 字數 2510 閱讀 2342

2023年12月13日 21:47:03 helloworld搬運工 閱讀數 3365 標籤: 資料庫 更多

一、併發業務場景

庫存業務,stock(sid, num),其中:

如上圖所示,兩個併發的查詢庫存操作,同時從資料庫都得到了庫存是5。

接下來使用者發生了併發的庫存扣減動作:

如上圖所示:

這兩個設定庫存的介面併發執行,庫存會先變成2,再變成3,導致資料不一致(實際賣出了5件商品,但庫存只扣減了2,最後一次設定庫存會覆蓋和掩蓋前一次併發操作)

二、不一致原因分析

出現資料不一致的根本原因,是設定操作發生的時候,沒有檢查庫存與查詢出來的庫存有沒有變化,理論上:

實際執行的時候:

三、cas優化

大家常說的「compare and set」(cas),是一種常見的降低讀寫鎖衝突,保證資料一致性的樂觀鎖機制。

針對上述庫存扣減的例子,cas公升級很容易,將庫存設定介面執行的sql:

update stock set num=$num_new where sid=$sid

公升級為:

update stock set num=$num_new where sid=$sid and num=$num_old

即可。四、什麼是aba問題

cas樂觀鎖機制確實能夠提公升吞吐,並保證一致性,但在極端情況下可能會出現aba問題。

什麼是aba問題?

考慮如下操作:

上述併發環境下,併發1在修改資料時,雖然還是a,但已經不是初始條件的a了,中間發生了a變b,b又變a的變化,此a已經非彼a,資料卻成功修改,可能導致錯誤,這就是cas引發的所謂的aba問題。

庫存操作,出現aba問題並不會對業務產生影響。

再看乙個堆疊操作的例子:

併發1(上):讀取棧頂的元素為「a1」

併發2:進行了2次出棧

併發3:又進行了1次出棧

併發1(下):實施cas樂觀鎖,發現棧頂還是「a1」,於是修改為a2

此時會出現系統錯誤,因為此「a1」非彼「a1」

五、aba問題的優化

aba問題導致的原因,是cas過程中只簡單進行了「值」的校驗,再有些情況下,「值」相同不會引入錯誤的業務邏輯(例如庫存),有些情況下,「值」雖然相同,卻已經不是原來的資料了。

優化方向:cas不能只比對「值」,還必須確保的是原來的資料,才能修改成功。

常見實踐:「版本號」的比對,乙個資料乙個版本,版本變化,即使值相同,也不應該修改成功。

庫存的併發讀寫例子,引入版本號的具體實踐如下:

(1)庫存表由

stock(sid, num)

公升級為stock(sid, num, version)

(2)查詢庫存時同時查詢版本號

select num from stock where sid=$sid

公升級為select num, version from stock where sid=$sid

假設有併發操作,都會將版本號查詢出來

(3)設定庫存時,必須版本號相同,並且版本號要修改

舊版本「值」比對cas

update stock set num=$num_new where sid=$sid and num=$num_old

公升級為「版本號」比對cas

此時假設有併發操作,第乙個操作,比對版本號成功,於是把庫存和版本號都進行了修改。

同時存在的第二個併發操作,比對版本號發生了變化,也是庫存應該修改失敗。

六、總結

CAS的ABA問題詳解

aba問題 執行緒1搶先獲得cpu時間片,而執行緒2因為其他原因阻塞了,執行緒1取值與期望的a值比較,發現相等然後將值更新為b,然後這個時候出現了執行緒3,期望值為b,欲更新的值為a,執行緒3取值與期望的值b比較,發現相等則將值更新為a,此時執行緒2從阻塞中恢復,並且獲得了cpu時間片,這時候執行緒...

CAS的ABA問題詳解

在多執行緒場景下cas會出現aba問題,關於aba問題這裡簡單科普下,例如有2個執行緒同時對同乙個值 初始值為a 進行cas操作,這三個執行緒如下 1.執行緒1,期望值為a,欲更新的值為b 2.執行緒2,期望值為a,欲更新的值為b 執行緒1搶先獲得cpu時間片,而執行緒2因為其他原因阻塞了,執行緒1...

併發程式設計cas的aba問題

多執行緒環境下,兩個執行緒a,b可能會對共享資料m進行操作。為了保證乙個執行緒在讀到資料跟寫入資料之間沒有被其他執行緒修改過,使用cas解決。cas 更改之前先判斷舊值是否有變化,如果沒有變化,認為沒有執行緒對該共享值做過操作。這種認為是有一下問題的,時執行緒a 執行緒bt1 讀m值為1 t2讀m值...