ReentrantLock加鎖流程

加鎖成功流程

20張圖帶你徹底瞭解ReentrantLock加鎖解鎖的原理_阿Q説代碼的技術博客_#鎖


其實就是把state改為1,然後設置ExclusiveOwnerThread為當前線程 ** 加鎖失敗流程**

20張圖帶你徹底瞭解ReentrantLock加鎖解鎖的原理_阿Q説代碼的技術博客_#ReentrantLock_02

  1. 進入tryAcquire邏輯,這是state已經是1,結果仍然失敗
  2. 接下來進入addWaiter邏輯,構造Node隊列
  • 下圖中黃色三角表示該Node的waitStatus狀態,其中0為默認正常狀態
  • Node的創建是懶惰的
  • 其中第一個Node成為Dummy,用來佔位,並不關聯線程

20張圖帶你徹底瞭解ReentrantLock加鎖解鎖的原理_阿Q説代碼的技術博客_#ReentrantLock_03


當前線程進入acquireQueued的邏輯

20張圖帶你徹底瞭解ReentrantLock加鎖解鎖的原理_阿Q説代碼的技術博客_#java_04

  1. acquireQueued會在第一個死循環中不斷嘗試獲得鎖,失敗後進入park阻塞
  2. 如果自己緊鄰着head(排第二位),那麼再次tryAcquire嘗試獲取鎖,當然這時state仍為1,失敗
  3. 進入shouldParkAfterFailedAcquire邏輯,將前驅node,即head的waitStatus改為-1,這次返回false

20張圖帶你徹底瞭解ReentrantLock加鎖解鎖的原理_阿Q説代碼的技術博客_#juc_05

  1. shouldParkAfterFailedAcquire執行完畢回到acquireQueued(因為是死循環),再次tryAcquire嘗試獲取鎖,當然這時state仍為1,失敗
  2. 當再次進入shouldParkAfterFailedAcquire時,這是因為其前驅node的waitStatus已經是-1,這次返回true
  3. 進入parkAndCheckInterrupt,Thread-1 park(灰色表示)

20張圖帶你徹底瞭解ReentrantLock加鎖解鎖的原理_阿Q説代碼的技術博客_#鎖_06

ReentrantLock解鎖後是怎麼競爭的?

解鎖競爭成功

![]()


20張圖帶你徹底瞭解ReentrantLock加鎖解鎖的原理_阿Q説代碼的技術博客_#juc_07

20張圖帶你徹底瞭解ReentrantLock加鎖解鎖的原理_阿Q説代碼的技術博客_#ReentrantLock_08

20張圖帶你徹底瞭解ReentrantLock加鎖解鎖的原理_阿Q説代碼的技術博客_#java_09


此時Thread-0釋放鎖,進入tryRelease流程,如果成功

  • 設置exclusiveOwnerThread為null
  • state=0

20張圖帶你徹底瞭解ReentrantLock加鎖解鎖的原理_阿Q説代碼的技術博客_#後端_10

  • 當前隊列不為null,並且head的waitStatus=-1,進入unparkSuccessor流程
  • 找到隊列中離head最近的一個Node(沒取消的),unpark恢復其運行,本例中即為Thread-1
  • 回到Thread-1的acquireQueued流程

20張圖帶你徹底瞭解ReentrantLock加鎖解鎖的原理_阿Q説代碼的技術博客_#後端_11


此時Thread-1的Node在下一次進入循環的時候發現tryAcquire成功了,會設置

- <font style="color:rgb(38, 38, 38);">exclusiveOwnerThread為Thread-1,state=1</font>
- <font style="color:rgb(38, 38, 38);">head指向剛剛Thread-1所在的Node,該Node清空Thread</font>
- <font style="color:rgb(38, 38, 38);">原本的head因為從鏈表斷開,可以被垃圾回收</font>

解鎖競爭失敗
如果這時候有其他線程來競爭(非公平的體現),例如這時有Thread-4來了

20張圖帶你徹底瞭解ReentrantLock加鎖解鎖的原理_阿Q説代碼的技術博客_#鎖_12


如果不巧又被Thread-4搶先

- <font style="color:rgb(38, 38, 38);">Thread-4被設置為exclusiveOwnerThread,state=1,</font>
- <font style="color:rgb(38, 38, 38);">Thread-1再次進入acquireQueued流程,獲取鎖失敗,重新進入park阻塞</font>

總結

這篇文檔主要介紹了Java中ReentrantLock的加鎖和解鎖流程,包括成功和失敗的情況。以下是文檔的重點概括:

ReentrantLock加鎖流程

加鎖成功
  1. 將state設置為1。
  2. 設置ExclusiveOwnerThread為當前線程。
加鎖失敗
  1. 進入tryAcquire邏輯,如果state已經是1,則失敗。
  2. 進入addWaiter邏輯,構造Node隊列。
  • Node的創建是懶惰的。
  • 第一個Node成為Dummy,不關聯線程。
  1. 當前線程進入acquireQueued邏輯。
  • 在死循環中嘗試獲取鎖,失敗則進入park阻塞。
  • 如果自己緊鄰着head(排第二位),再次嘗試tryAcquire獲取鎖。
  • 將前驅node(head)的waitStatus設置為-1。
  • 進入parkAndCheckInterrupt,線程park。

ReentrantLock解鎖後的競爭

解鎖競爭成功
  1. Thread-0釋放鎖,進入tryRelease流程。
  • 設置exclusiveOwnerThread為null。
  • state設置為0。
  • 如果當前隊列不為null,並且head的waitStatus為-1,進入unparkSuccessor流程。
  • 找到隊列中離head最近的一個Node(未取消的),unpark恢復其運行(例如Thread-1)。
  • Thread-1的Node在下一次循環時發現tryAcquire成功,設置exclusiveOwnerThread為Thread-1,state為1,head指向Thread-1所在的Node。
解鎖競爭失敗
  1. 如果有其他線程(如Thread-4)競爭。
  • Thread-4可能搶先設置為exclusiveOwnerThread,state為1。
  • Thread-1再次進入acquireQueued流程,獲取鎖失敗,重新進入park阻塞。

這篇文檔詳細描述了ReentrantLock在加鎖和解鎖過程中的內部機制,包括狀態的變更、隊列的構造、線程的阻塞和喚醒等關鍵步驟。