樂觀鎖常見的兩種實現方式和適用場景


1、版本號機制

    一般是在數據表中加上一個版本號version字段,表示數據被修改的次數,當數據被修改時,version值會加一。當線程A要更新數據值時,在讀取數據的同時也會讀取version值,在提交更新時,若剛才讀到的version值與當前數據庫中的version值相等時才更新,否則重試更新操作,直到更新成功。

 

舉一個簡單的例子:

假設數據庫中賬戶信息表中有一個version字段,當前值為1;而當前賬戶余額字段為100;

1、操作員A此時將其讀出(version=1),並從其賬戶余額中扣除50(100-50);

2、在操作員A操作的過程中,操作員B也讀入此用戶信息(version=1),並從其賬戶余額中扣除20(100-20);

3、操作員A完成了修改操作,將數據版本號+1(version=2),連同賬戶扣除后余額(子段=50),提交至數據庫更新,此時由於 提交數據庫版本大於數據庫當前記錄的版本,數據被更新,數據庫記錄version更新為2.

4、操作員B完成了操作,也將版本號+1(version=2)試圖向數據庫提交數據(子段=80),但此時比對數據庫記錄版本時發現,操作員B提交的數據版本號為2,數據庫記錄當前版本也為2,不滿足“提交版本必須大於記錄當前版本才能執行更新”的樂觀鎖策略,因此,操作員B的提交被駁回。

這樣就避免了操作員B用基於version=1的舊數據修改的結果覆蓋操作員A的操作結果的可能。

2、CAS算法

即compare and swap(比較和互換),是一種有名的無鎖算法。無鎖編程,即不使用鎖的情況下實現多線程之間的變量同步,也就是在沒有線程被阻塞的情況下實現變量的同步,所以也叫非阻塞同步。CAS算法涉及到3個操作數。

1、需要讀寫的內存值V

2、進行比較的值A

3、擬寫入的新值B

當且僅當V的值等於A時,CAS通過原子方式用新值B來更新V的值,否則不會執行任何操作(比較和替換是一個原子操作)。一般情況下是一個自旋操作,即不斷的重試。

 

CAS和synchronized的使用場景

1、對於資源競爭較少(線程沖突較輕)的情況,使用synchronized同步鎖進行線程阻塞和喚醒切換以及用戶內核態間的切換操作額外浪費消耗cpu資源;而CAS基於硬件實現,不需要進入內核,不需要切換線程,操作自旋幾率較少,因此可以獲得更高的性能。

2、對於資源競爭嚴重(線程沖突嚴重)的情況,CAS自旋的概率會比較大,從而浪費更多的CPU資源,效率低於synchronized。

補充:Java並發編程這個領域中synchronized關鍵字一直都是元老級的角色,很久之前很多人都會稱他為“重量級鎖”。但是,在JavaSE1.6之后進行了主要包括為了減少獲得鎖和釋放鎖帶來的性能消耗而引入了偏向鎖和輕量級鎖以及其他各種優化之后變得在某些情況下並不是那么重了。

synchronized的底層實現主要依靠lock-Free隊列,基本思路是自旋后阻塞,競爭切換后繼續競爭鎖,稍微犧牲了公平性,但獲得了高吞吐量。在線程沖突較少的情況下,可以獲得和CAS類似的性能;而線程沖突嚴重的情況下性能遠高於CAS。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM