多線程等待喚醒機制
介紹
線程間通信方式
1、全局變量(基于記憶體共享)
2、Message消息機制
備注:基于記憶體共享比較容易實作
如果多線程隻是處理完全相同的任務時,那麼事情就簡單了,似乎也不需要線程之間互相協同。
如果多線程處理的業務需要互相協同的話,那麼線程之間就要進行協同和通信了。
最典型的例子就是生産者和消費者模型。
Java在Object對象中就定義了幾個關于等待喚醒機制的方法
1、public final void wait()
//使目前線程處于等待狀态,直到其它線程調用notify或notifyAll方法喚醒
//簡單說就是釋放鎖資源執行權,等其它線程通知喚醒它。
2、public final native void notify()
//喚醒在此對象螢幕上等待的單個線程
3、public final native void notifyAll()
//喚醒在此對象螢幕上等待的所有線程
備注:以上三個方法都是隻有在持有對象螢幕時才可以調用,否則報錯。通常是在同步代碼塊中使用。
它們的作用對象也隻能是監視本對象的線程,不能作用于其它無關線程。
wait():等待,将正在執行的線程釋放其執行資格和執行權,并存儲到線程池中。
notify():喚醒,喚醒線程池中被wait()的線程,一次喚醒一個,而且是任意的。
notifyAll():喚醒全部:可以将線程池中的所有wait() 線程都喚醒。
這三個方法被定義在了Object類中,為什麼這些操作線程的方法定義在Object類中?
因為這些方法在使用時,必須要标明所屬的鎖,而鎖又可以是任意對象。能被任意對象調用的方法一定定義在Object類中。
等待和喚醒機制詳解
舉個例子
如果有兩個人A、B,他們要完成清潔盤子工作,如果他們都一起洗,洗完之後一起擦幹那麼他們就屬于多線程處理相同的任務,
他們之間并沒有協同和資訊交流。
如果A負責洗盤子,B負責擦盤子,那麼他們之間就存在協同和資訊傳遞了。當A洗完一個盤子之後,它會通知B,
此時A接到通知之後又開始洗盤子了,如此循環下去直到洗完為止。
備注:這就是一個生産者和一個消費者時候的模型
如果有A、B、C、D四個人,A、B負責洗盤子,C、D複雜擦幹盤子,剛開始A洗一個盤子,通知C、D,此時C、D決定C先擦盤子D先休息,
C擦完之後通知A、B,這時B開始洗盤子A休息,B洗完之後通知C、D,此時D擦盤子C休息,依次循環下去知道任務完成。
備注:這就是多個生産者和多個消費者模型
以上的三種模型都是針對每次隻能洗一個盤子和隻能擦幹一個盤子的情況(比如臨時中間盤架隻有一個放盤子的位置)
實際開發和場景中,往往都是生産者一直生産,将生産好的産品放到一個隊列容器中,消費者就隻觀察隊列,如果隊列中有産品就消費。
這樣就是生産者和消費者之間免去了不必要的資訊交流,也就是解耦合了。
備注:實際開發中使用消息中間件場景比較多。
總結
多線程如果是存在協同處理任務的話,處理不好容易出現死鎖。
是以在處理這種問題時要分析清楚何時等待何時喚醒,即線程間通信要清晰明了。