Udemy Course Multithreading, Concurrency & Performance 28

Inter-thread Review And Condition Variable(Inter-thread Communication)

ZONGRU Li
Sep 21, 2021

過去章節有介紹過一些Inter-thread:

  1. Thread.interrupt(),A Thread可以中斷B Thread
  2. Thread.join(),在A Thread內做BThread.join(),A會等B做完才繼續
  3. Semaphore在不同Thread間acquire()與release()

接著介紹另個一般Inter-thread communication=>Condition variables

(java.util.concurrent.locks.Condition)

狀況情境如下:

比如A Thread先執行確認條件

接著B Thread執行

再接著A Thread拿到訊號後,可以再次重新確認Condition

Condition Variable都會搭配lock使用,以確保”Check “是atomic!

實際Code與可能情境寫法如下(配合Reentrant lock)

考量到一個簡單的帳號密碼檢核

通常User在前端UI介面上敲定帳號與密碼後

送到後端系統,我們會實際把帳密拿去DB比對

但是拿去跟DB內資料比對這件事是貴的

所以至少後端系統至少確定過來的帳號與密碼不是null後才去跟DB資料比對

初步寫法如下:

上圖當某Thread進去while迴圈檢核到當前的帳號或密碼有null時

會停止在condition.await() =>等待別的Thread發送signal再次while檢核

並且執行await()的Sleep前,背後連帶會執行lock.unlock()

此時UI Thread如下右邊執行

上圖UI Thread進到lock.lock()內

在拿到User輸入的帳號密碼後會走到condition.signal()發送訊號

但是有個重點是這個condition.signal()只會給單一個在await()的Thread訊號

只有ONLY ONE會收到訊號(i.e.多個都在await()的Threads只有一個會拿到)

接著

當然也可能User沒填好,送來的帳密還有null,就繼續做while loop

其中有個問題在finally又做了unlock()

也就是在做doStuff()前又做了unlock,講師回應如下

by Michael Question link

結論:

Condition.await(),與其他型式的await()

  • void await() — unlock lock(所以另一個UI Thread才能鎖住Resource物件的帳號密碼)並Sleep,wait until signaled
  • long awaitNanos(long NanosTimeout) — wait no longer than nanosTimeout
  • boolean await(long time,TimeUnit unit) — wait no longer than time,in given time units
  • boolean awaitUntil(Data deadline) — wake up before deadline date

Condition.signal()

  • void signal() — 喚醒正在等待condition variable的"一個"Thread
  • 一個單一Thread要被喚醒,需要拿到condition variable相關的lock
  • 若當下沒有Thread在等待condition variable,則signal()發動不做任何事!

Condition.signalAll()

  • 直接廣播一個signal()給所有Thread,尤其是正在等待condition variable的
  • 執行signalAll()的Thread不用瞭解當下多少個Thread卡在await(),甚至不需要知曉有多少Thread存在,跑了就對了!(另一個跟Semaphore差異,Semaphore做release還要一個個去執行)

後記,事後對await()背後動作研究了一下,確定的動作是

左邊Thread進到await()

  1. await()內會先執行lock.unlock() -->右邊Thread才能進得去lock.lock()
  2. 接著右邊發動signal導致左邊Thread甦醒等待離開await(),但需要取回lock
  3. 右邊Thread跑完signal()後走到finally區塊的lock.unlock()
  4. 左邊Thread才真的可以離開await()

(但是只知道左邊Thread這時要拿著lock,看邏輯來說應該有做lock.lock())

5. 接著左邊Thread進到下一輪while判斷式,若因為不符合,不在進到await()

6.所以左邊Thread最終走到finally區塊的lock.unlock() ←邏輯上這是await()鎖上的

看到原生Java doc只提到await()甦醒後要拿到鎖

await()甦醒後到底有沒重作lock.lock()不確定

以下這課程影片都學生提問,講師給的範例code,供研究await()行為

從debug mode找到實際class

最後發現我要的解答在底下留言問題中:

隔壁Thread signal來後就會再做lock(i.e. lock.lock())

參考課程

--

--

ZONGRU Li
ZONGRU Li

Written by ZONGRU Li

2022/11/17 開源部分個人筆記給LINE "Java程式語言討論區"社群,希望能對社群的技術學習做一點點貢獻.(掩面....記得退訂閱!

No responses yet