樂觀鎖與悲觀鎖的總結

樂觀鎖

定義

在操作時持樂觀態度,認爲操作時其它線程不會修改數據,因此不會鎖定數據,但是在更新數據時會用版本號或者CAS算法判斷數據在本次操作過程中是否被更改,如果被更改,則修改失敗。

所以樂觀鎖雖然名字帶鎖,但是實際上並不會對數據進行鎖定操作,其它線程仍然可以自由地讀寫數據,不會造成死鎖等問題。

適用場景

樂觀鎖不會鎖定數據,所以其它需要讀取數據的線程不需要等待,但是如果更新頻繁,頻繁地出現修改失敗回滾的情況,反而會導致性能及使用體驗的問題。

因此樂觀鎖適用於需要頻繁讀取數據,但是較少更新數據的場景。

實際應用

Java中原子變量使用了CAS算法來避免加鎖,同時保證數據修改的正確性:

  1. 使用volatile聲明該變量爲線程間共享變量;

  2. 使用CAS算法保證變量修改的正確性,我們可以調用compareAndSet函數來嘗試修改原子變量,該函數會返回修改的結果,如果成功,則操作完成,如果失敗則獲取新值處理後繼續嘗試;

實現方式

樂觀鎖通常有兩種實現方式:

  1. 通過版本號機制實現;
  2. 通過CAS(compare and swap)算法實現;

版本號機制實現

  1. 取出數據時同時獲取數據當前的version;
  2. 更新數據時也帶上這個version;
  3. 服務端比對請求的version與目前數據的version是否一致;
  4. 如果一致,則更新數據,如果不一致,則修改失敗;

CAS算法實現

CAS算法簡介

CAS是compare and swap的縮寫,算法邏輯就是當一個線程要修改某個數據時,需要攜帶上之前的原數據,服務端會將這個原數據與當前數據進行比對,如果一致,則將當前數據替換爲申請修改的數據,如果不一致,則修改失敗。

ABA問題

  • 線程T1與T2均取出A數據;
  • T1要將A數據更新爲B,而此時T2速度更快,將數據從A更新爲了C,然後又將C更新爲了A;
  • T1的更新請求到達服務端,服務端比對T1攜帶的原數據A與當前數據A,結果相等,於是將數據更新爲了B,但實際數據已經幾經變化了;

在大多數情況下,這都是沒有問題的,但如果我們需要嚴格保證原數據未經變動時,則可能出現問題,相比較使用版本號實現的樂觀鎖則可以避免此問題。

悲觀鎖

定義

在操作時持悲觀態度,認爲其它線程會修改數據,所以更新數據時對數據進行鎖定,加鎖後,同一時間只能有一個線程執行,其它線程只能等待直到鎖被其它線程釋放。

適用場景

悲觀鎖可以保證數據操作時的正確性,不會出現數據因被其它線程修改而失敗的情況,但是它會限制其它線程讀取數據。

所以悲觀鎖更適用於修改頻繁,使用樂觀鎖會頻繁衝突回滾,但讀取較少的場景。

實際應用

Java的synchronized關鍵字就是一種悲觀鎖

參考文章

樂觀鎖、悲觀鎖,這一篇就夠了!

原子操作CAS及其實現類

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章