天天看點

淺聊一下,可中斷鎖(ReentrantLock)

前言

今天早上上廁所,上的我痔瘡犯了,屁股一坐下去就感覺一根針在刺我,得的是外痔,之前還堅持用痔瘡膏來着,但是感覺塗藥的那個姿勢以及位置我實在無法忍受,就把它給斷了,到頭來還是屁股糟了罪,

什麼是可中斷鎖?

再說起 ReentrantLock 的時候可能很多人第一時間想到的是公平、非公平鎖,但是 ReentrantLock 豐富的 api 可不止于此哦,可中斷鎖顧名思義,就是在競争鎖等待的時間太久,我們開發人員可以調用 interrupt(英特入譜特)方法讓 lockInterruptibly (加鎖可中斷)方法抛出異常,讓線程主動退出等待的過程,去做别的事情。

可中斷鎖應用

threadOne 進行 lockInterruptibly 加鎖操作,由于鎖一直被 threadOne 占用,當 threadTwo 開始進行 lockInterruptibly 加鎖的時候,由于鎖還在 threadOne 這,threadOne 會一直處于一個等待的狀态,如果 threadOne 一直沒有調用 unlock 方法,那麼 threadTwo 會一直休眠,直至等到 unlock、或者 threadOne.interrupt() 方法才會再次被喚醒進行工作,而 ReentrantLock 顯然也是考慮到了這一點,在 lockInterruptibly 方法裡面,如果線程被喚醒後,會對線程的中斷狀态進行一個判斷,如果線程被中斷了,則會抛出一個異常,這樣一來,就避免了 threadTwo 一直等待的現象出現了。

淺聊一下,可中斷鎖(ReentrantLock)

lockInterruptibly 源碼剖析

點進入口中可以看到,是利用了 sync 裡面的一個類實作的

淺聊一下,可中斷鎖(ReentrantLock)

而 sync 繼承了 AQS (AbstractQueuedSynchronizer),哦吼又是借助 AQS 實作的。接下來我們隻需分析 AQS 中的 acquireInterruptibly 方法就好了。

淺聊一下,可中斷鎖(ReentrantLock)

可以看到,如果是一個中斷狀态的線程去使用 lockInterruptibly 方法會直接抛出異常的,開發的時候要注意!裡面的 tryAcquire 方法在我們分析公平、非公平鎖的時候就已經分析過了,不做剖析。可以點選 ReentrantLock源碼探究、探究公平鎖與非公平鎖背後的奧秘 進行閱讀。那麼就隻剩下 doAcquireInterruptibly 了。

淺聊一下,可中斷鎖(ReentrantLock)

doAcquireInterruptibly 源碼剖析

這段代碼其實也在 ReentrantLock源碼探究、探究公平鎖與非公平鎖背後的奧秘 這篇文章裡面分析過了。和 AQS 中的 acquireQueued 這個方法邏輯一樣,唯一有差別的地方就是,線程被喚醒後 doAcquireInterruptibly 會直接抛出一個異常,而 acquireQueued 則不會。

淺聊一下,可中斷鎖(ReentrantLock)

下面我貼一張我自己的截圖,友善日後閱讀~~~~~,到此 ReentrantLock 是可中斷鎖的秘密已經解開了。

淺聊一下,可中斷鎖(ReentrantLock)

線程中的 interrupt、park、interrupted、isInterrupted 是什麼?

一個簡單的小例子直覺感受一下,threadOne 裡面調用 parkAndCheckInterrupt 方法進行休眠(阻塞)線程的操作,然後等待被喚醒,過了 10 秒鐘後 threadOne 自己調用了 interrupt 方法,将 park 休眠狀态下的自己給喚醒了。值得一提的是 interrupted 方法被調用後,線程的中斷狀态會立即反轉一次,之後看自己的中斷狀态即為反轉後的狀态。而且喚醒 threadOne 的方式不止一種,還可以使用 LockSupport.unpark(threadOne);

淺聊一下,可中斷鎖(ReentrantLock)

運作結果

淺聊一下,可中斷鎖(ReentrantLock)