Java鎖最全詳解:樂觀鎖/悲觀鎖+公平鎖/非公平鎖+獨享鎖/共享鎖

ITPUB社群發表於2023-01-06

在高併發的場景裡,除了昨天談到的MySQL最全鎖詳解:行鎖、表鎖、悲觀鎖、樂觀鎖、共享鎖,非常影響併發效能之外。


還有今天我要談到的Java併發場景裡的各種鎖,鎖的衝突同樣是影響併發訪問效能的另外一種核心因素,同樣的重要,只不過一個是針對資料庫的場景,另外一個是針對Java併發場景。


今天接著分享Java併發程式設計裡的鎖,這樣可以形成系統的高併發鎖系列,希望對大家掌握好高併發有所幫助

Java鎖最全詳解:樂觀鎖/悲觀鎖+公平鎖/非公平鎖+獨享鎖/共享鎖


樂觀鎖 VS 悲觀鎖

樂觀鎖與悲觀鎖是一種廣義上的概念,在Java併發程式設計和資料庫中都有實際的應用場景。

1.樂觀鎖

顧名思義,就是很樂觀,每次去拿資料的時候都認為別人不會修改,所以不會上鎖,但是在更新的時候會判斷一下在此期間別人有沒有去更新這個資料,可以使用版本號等機制來實現。

Java鎖最全詳解:樂觀鎖/悲觀鎖+公平鎖/非公平鎖+獨享鎖/共享鎖

比如典型的應用就是Java併發裡的CAS實現,Java併發包中的很多類都使用了CAS技術,是實現樂觀鎖的核心操作。

CAS全稱 Compare And Swap(比較與交換),是一種無鎖演算法。

簡單來說,CAS演算法有3個三個運算元:

  • 需要讀寫的記憶體值 V

  • 進行比較的值 A

  • 要寫入的新值 B

當且僅當預期值A和記憶體值V相同時,將記憶體值V修改為B,否則返回V。

這是一種樂觀鎖的思路,它相信在它修改之前,沒有其它執行緒去修改它。

2.悲觀鎖

而悲觀鎖恰恰相反,它認為在它修改之前,一定會有其它執行緒去修改它,所以每次在拿資料的時候都會上鎖。

Java鎖最全詳解:樂觀鎖/悲觀鎖+公平鎖/非公平鎖+獨享鎖/共享鎖

典型代表就是一篇我談到的Synchronized的底層實現原理,就是典型的悲觀鎖。

 這與MySQL的悲觀鎖、樂觀鎖,都是同樣的應用場景,大家的實現思路也同樣類似,其實很多技術都是互相參考的。


公平鎖 VS 非公平鎖

1.公平鎖

Java鎖最全詳解:樂觀鎖/悲觀鎖+公平鎖/非公平鎖+獨享鎖/共享鎖

就是很公平,在併發環境中,每個執行緒在獲取鎖時會先檢視此鎖維護的等待佇列,如果為空,或者當前執行緒是等待佇列的第一個,就佔有鎖,否則就會加入到等待佇列中,以後會按照FIFO的規則從佇列中取到自己。

公平鎖的應用

java jdk併發包中的ReentrantLock可以指定建構函式的boolean型別來建立公平鎖,比如:公平鎖可以使用new ReentrantLock(true)實現。

2.非公平鎖

非公平鎖上來就直接嘗試佔有鎖,如果嘗試失敗,就再採用類似公平鎖那種方式。

非公平鎖的優點是可以減少喚起執行緒的開銷,整體的吞吐效率高,因為執行緒有機率不阻塞直接獲得鎖,CPU不必喚醒所有執行緒,缺點是處於等待佇列中的執行緒可能會餓死,或者等很久才會獲得鎖。

Java鎖最全詳解:樂觀鎖/悲觀鎖+公平鎖/非公平鎖+獨享鎖/共享鎖

非公平鎖的應用

java jdk併發包中的ReentrantLock的建構函式的預設就是採用非公平鎖的實現,使用new ReentrantLock(false)來實現,與上面的公平鎖相反的宣告方式。

 

獨享鎖 VS 共享鎖

1.獨享鎖

是指該鎖一次只能被一個執行緒所持有,比如:剛剛談到的ReentrantLock就是獨享鎖

Java鎖最全詳解:樂觀鎖/悲觀鎖+公平鎖/非公平鎖+獨享鎖/共享鎖

2.共享鎖

是指該鎖可被多個執行緒所持有,Lock的另一個實現類ReadWriteLock,其讀鎖就是共享鎖,其寫鎖卻是獨享鎖。

Java鎖最全詳解:樂觀鎖/悲觀鎖+公平鎖/非公平鎖+獨享鎖/共享鎖

ReadWriteLock的讀鎖(共享鎖)可保證併發讀是非常高效,但讀寫,寫讀 ,寫寫的過程是互斥的。

這樣設計的原因是:就是盡最大的解放併發讀的操作,因為讀佔據了更大的訪問請求,我只會在涉及少部分寫的操作的時候,才考慮獨享鎖,從而提升併發的效率。

這樣的設計理念,其本質就是要讀寫分離,也許你也會想到資料庫的讀寫分離機制。

技術有意思的地方就是在於,很多技術方案雖然實現不一樣,但是背後的設計理念往往都是相同的,完全可以互相借鑑與融會貫通。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/70024420/viewspace-2931138/,如需轉載,請註明出處,否則將追究法律責任。

相關文章