🌟我的其他文章也講解的比較有趣😁,如果喜歡博主的講解方式,可以多多支持一下,感謝🤗!
🌟了解 ThreadLocal請看: ThreadLocal有趣講解,小白也能聽懂!
其他優質專欄: 【🎇SpringBoot】【🎉多線程】【🎨Redis】【?設計模式專欄(已完結)】…等
如果喜歡作者的講解方式,可以點贊收藏加關注,你的支持就是我的動力
?更多文章請看個人主頁: 碼熔burning
想象一下,有一個很受歡迎的公共廁所 🚽,同一時間只能一個人進去。
ReentrantLock
就好比是這個廁所的門鎖管理員。他負責管理誰能進去。
深入了解 ReentrantLock 請看:ReentrantLock:可定制的“VIP 包間”
核心原理:AQS
ReentrantLock
的底層依賴一個叫做 AQS 的框架。你可以把 AQS 理解為一個通用的排隊和狀態管理系統。
- 狀態 (State): AQS 內部有一個
state
變量(是個整數)。在ReentrantLock
里:state = 0
: 表示廁所現在沒人,門是空閑的 ?。state > 0
: 表示廁所有人,門被占用了 🔒。這個數字還表示同一個人重復進入(重入)了多少次。比如一個人進去后,又在里面鎖了一層門,state
就變成 2。
- 等待隊列 (Queue): AQS 維護了一個等待隊列。這個隊列像銀行排隊的隊伍一樣,是先進先出 (FIFO) 的 🚶?♂?🚶?♀?🚶?♂?。想上廁所但發現里面有人的人(線程),就會被安排到這個隊列里排隊等著。
非公平鎖 (Nonfair Lock) - 默認模式
- 解釋: 就像一個秩序不太好的廁所。
- 當你(線程)想上廁所時,你首先會沖到門口 🏃💨,猛地推一下門,看看是不是正好沒人(嘗試用 CAS 原子操作直接把
state
從 0 改成 1)。 - 如果正好沒人,恭喜你 🎉,你直接就進去了!哪怕旁邊已經有人在排隊等了很久,你也可能因為動作快而“插隊”成功。
- 如果里面有人(推門失敗,
state
不是 0),或者你嘗試搶鎖的那一下正好別人也搶成功了,那你沒辦法 😟,只能乖乖去隊伍(AQS 隊列)后面排著。 - 當里面的人出來(釋放鎖)時,管理員(AQS)會喚醒 ? 隊伍最前面的人。但是,與此同時,如果又有一個新人跑過來直接推門 🏃💨,并且正好成功了,那這個剛被喚醒、正準備進去的人可能又得等一下。
- 當你(線程)想上廁所時,你首先會沖到門口 🏃💨,猛地推一下門,看看是不是正好沒人(嘗試用 CAS 原子操作直接把
- 底層實現關鍵點:
- 調用
lock()
時,先嘗試直接獲取鎖(CAS 修改state
)。 - 獲取失敗,才把自己加入 AQS 等待隊列。
- 釋放鎖時,喚醒隊頭節點,但新來的線程仍有機會搶先獲取鎖。
- 調用
- 優點: 可能性能更好,吞吐量更高 🚀。因為減少了線程掛起和喚醒的次數(如果運氣好直接搶到鎖,就不用排隊和被喚醒了)。
- 缺點: 可能導致饑餓 😩。排在前面的線程可能一直等不到鎖,因為總有新來的線程“插隊”成功。
公平鎖 (Fair Lock)
- 解釋: 就像一個非常有秩序的廁所 👍。
- 當你(線程)想上廁所時,你首先會看一眼 👀 隊伍前面有沒有人排隊 (
hasQueuedPredecessors()
檢查)。 - 如果隊伍里有人,對不起 🙅?♂?,你不能直接去推門,必須老老實實去隊伍(AQS 隊列)后面排著 🚶?♂?🚶?♀?。
- 只有當隊伍是空的,你才可以去嘗試推門(嘗試 CAS 修改
state
)。 - 當里面的人出來(釋放鎖)時,管理員(AQS)只會喚醒隊伍最前面的那個人,并且只有這個人能進去。新來的人?對不起,看隊伍里有人,請自覺排隊。
- 當你(線程)想上廁所時,你首先會看一眼 👀 隊伍前面有沒有人排隊 (
- 底層實現關鍵點:
- 調用
lock()
時,先檢查 AQS 隊列中是否有等待者。 - 如果有等待者,則不嘗試獲取鎖,直接加入隊列尾部。
- 只有當隊列為空時,才嘗試獲取鎖。
- 釋放鎖時,嚴格喚醒并讓隊頭節點獲取鎖。
- 調用
- 優點: 公平 ??,保證了先來后到,不會有線程餓死。
- 缺點: 性能相對較低,吞吐量可能不如非公平鎖 📉。因為即使鎖是空閑的,只要隊列里有人,新來的線程也得去排隊,導致更多的線程掛起和喚醒,增加了上下文切換的開銷。
總結一下 ??:
ReentrantLock
通過內部的 Sync
類(它繼承了 AQS)來實現鎖邏輯 🛠?。Sync
有兩個子類:NonfairSync
和 FairSync
。
- 核心區別在于嘗試獲取鎖 (
tryAcquire
方法) 時的行為:NonfairSync
: 直接嘗試 CAS 修改state
,失敗再入隊。FairSync
: 先檢查隊列是否為空或者自己是不是隊頭,滿足條件才嘗試 CAS 修改state
,否則直接入隊。
🤔 默認情況下,new ReentrantLock()
創建的是非公平鎖,因為它通常有更好的性能。如果你需要保證公平性,可以使用 new ReentrantLock(true)
來創建公平鎖。