執行緒間協作——wait、notify、notifyAll
在 Java 中,可以通過配合呼叫 Object 物件的 wait() 方法和 notify()方法或 notifyAll() 方法來實現執行緒間的通訊。線上程中呼叫 wait() 方法,將阻塞等待其他執行緒的通知(其他執行緒呼叫 notify() 方法或 notifyAll() 方法),線上程中呼叫 notify() 方法或 notifyAll() 方法,將通知其他執行緒從 wait() 方法處返回。
wait()
該方法用來將當前執行緒置入休眠狀態,直到接到通知或被中斷為止。在呼叫 wait()之前,執行緒必須要獲得該物件的物件級別鎖,即只能在同步方法或同步塊中呼叫 wait()方法。進入 wait()方法後,當前執行緒釋放鎖。
notify()
該方法也要在同步方法或同步塊中呼叫,即在呼叫前,執行緒也必須要獲得該物件的物件級別鎖。
該方法用來通知那些可能等待該物件的物件鎖的其他執行緒。如果有多個執行緒等待,則執行緒規劃器任意挑選出其中一個 wait()狀態的執行緒來發出通知,並使它等待獲取該物件的物件鎖(notify 後,當前執行緒不會馬上釋放該物件鎖,wait 所在的執行緒並不能馬上獲取該物件鎖,要等到程式退出 synchronized 程式碼塊後,當前執行緒才會釋放鎖,wait所在的執行緒也才可以獲取該物件鎖),但不驚動其他同樣在等待被該物件notify的執行緒們
notifyAll()
該方法與 notify ()方法的工作方式相同,重要的一點差異是:
notifyAll 使所有原來在該物件上 wait 的執行緒統統退出 wait 的狀態(即全部被喚醒,不再等待 notify 或 notifyAll,但由於此時還沒有獲取到該物件鎖,因此還不能繼續往下執行),變成等待獲取該物件上的鎖,一旦該物件鎖被釋放(notifyAll 執行緒退出呼叫了 notifyAll 的 synchronized 程式碼塊的時候),他們就會去競爭。如果其中一個執行緒獲得了該物件鎖,它就會繼續往下執行,在它退出 synchronized 程式碼塊,釋放鎖後,其他的已經被喚醒的執行緒將會繼續競爭獲取該鎖,一直進行下去,直到所有被喚醒的執行緒都執行完畢。
應該在while迴圈,而不是if語句中呼叫wait。if語句存在一些微妙的小問題,導致即使條件沒被滿足,你的執行緒你也有可能被錯誤地喚醒。所以如果你不線上程被喚醒後再次使用while迴圈檢查喚醒條件是否被滿足,你的程式就有可能會出錯。在while迴圈裡使用wait的目的,是線上程被喚醒的前後都持續檢查條件是否被滿足。如果條件並未改變,wait被呼叫之前notify的喚醒通知就來了,那麼這個執行緒並不能保證被喚醒,有可能會導致死鎖問題。參考《Effective Java》
示例
我之前寫過一篇文章 執行緒執行順序——CountDownLatch、join()、執行緒池 討論的是讓一個執行緒晚於其他執行緒最後執行。我想用wait和notify寫個例子讓一個執行緒先於其他執行緒執行。
程式碼場景:Worker類和Boss類都實現Runnable介面,但是老闆先安排完工作後,工人才能開始工作。
程式碼實現:
class Worker implements Runnable{
private String name;
private Object object;
public Worker(String name,Object object){
this.object = object;
this.name = name;
}
public void run(){
synchronized(object){
try {
object.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(name + " is working");
}
}
}
class Boss implements Runnable{
private String name;
private Object object;
public Boss(String name, Object object){
this.name = name;
this.object = object;
}
public void run(){
synchronized(object){
System.out.println(name + " has arranged the work");
object.notifyAll();
//object.notify();
}
}
}
public static void main(String[] args) throws Exception{
Object object = new Object();
new Thread(new Worker("work1", object)).start();
new Thread(new Worker("work2", object)).start();
new Thread(new Worker("work3", object)).start();
new Thread(new Boss("boss", object)).start();
}
執行結果:
boss has arranged the work
work3 is working
work2 is working
work1 is working
從上面的程式碼中可以看到,Boss類使用notifyAll()方法,3個worker執行緒都會執行,如果換成 notify()方法,則只有一個worker執行緒會執行。
完整程式碼在github的 https://github.com/lzx2011/java-scaffold
中的thread包中的 WaitAndNotify 類中。
應用
比如可以用wait和notify實現生產者和消費者,這裡不細說了,有空再寫下生產者和消費者吧。
總結
可以使用wait和notify函式來實現執行緒間通訊。
在synchronized的函式或物件裡使用wait、notify和notifyAll,否則Java虛擬機器會生成 IllegalMonitorStateException。
在while迴圈裡而不是if語句下使用wait。這樣,迴圈會線上程睡眠前後都檢查wait的條件,並在條件實際上並未改變的情況下處理喚醒通知。
在多執行緒間共享的物件(在生產者消費者模型裡即緩衝區佇列)上使用wait。
參考資料
執行緒間協作:wait、notify、notifyAll
如何在 Java 中正確使用 wait, notify 和 notifyAll – 以生產者消費者模型為例
相關文章
- 【Java】【多執行緒】兩個執行緒間的通訊、wait、notify、notifyAllJava執行緒AI
- 執行緒間的同步與通訊(2)——wait, notify, notifyAll執行緒AI
- Java多執行緒8:wait()和notify()/notifyAll()Java執行緒AI
- wait()和notify()、notifyAll()AI
- sleep & wait | notify | notifyAllAI
- Java 併發程式設計:執行緒間的協作(wait/notify/sleep/yield/join)Java程式設計執行緒AI
- java中關於執行緒間協作所用關鍵字synchronized,wait,notify的用法Java執行緒synchronizedAI
- wait/notify/notifyAll 總結AI
- 深入執行緒的wait()/notify()執行緒AI
- 併發程式設計——執行緒中sleep(),yield(),join(),wait(),notify(),notifyAll()區別程式設計執行緒AI
- 執行緒間協作執行緒
- java多執行緒wait notify joinJava執行緒AI
- wait、notify和notifyAll的關係AI
- 多執行緒中的wait與notify執行緒AI
- Java-併發-wait()、notify()和notifyAll()JavaAI
- 執行緒篇2:[- sleep、wait、notify、join、yield -]執行緒AI
- java多執行緒 wait() notify()簡單使用Java執行緒AI
- Java多執行緒的wait()和notify()例子Java執行緒AI
- Java通過wait()和notifyAll()方法實現執行緒間的通訊JavaAI執行緒
- Java多執行緒/併發11、執行緒同步通訊:notify、waitJava執行緒AI
- Java的wait(), notify()和notifyAll()使用心得JavaAI
- Java常用的三個方法 `wait ` `notify` `notifyAll`JavaAI
- Java多執行緒 -- wait() 和 notify() 使用入門Java執行緒AI
- 執行緒間的協作機制執行緒
- 如何在 Java 中正確使用 wait, notify 和 notifyAllJavaAI
- Java多執行緒中wait 和 notify 方法理解Java執行緒AI
- Java多執行緒中的wait/notify通訊模式Java執行緒AI模式
- 執行緒安全(三個條件)Synchronzied,wait和notify執行緒AI
- 手撕Java多執行緒(四)執行緒之間的協作Java執行緒
- 多執行緒(一)、基礎概念及notify()和wait()的使用執行緒AI
- java多執行緒基礎篇(wait、notify、join、sleep、yeild方法)Java執行緒AI
- Java多執行緒學習(四)等待/通知(wait/notify)機制Java執行緒AI
- 執行緒間協作-《thinking in java》讀書筆記(一)執行緒ThinkingJava筆記
- 執行緒間的協作(3)——管道輸入/輸出流執行緒
- java基礎知識回顧之java Thread類學習(七)--java多執行緒通訊等待喚醒機制(wait和notify,notifyAll)...Javathread執行緒AI
- muduo網路庫學習之EventLoop(二):程式(執行緒)wait/notify 和 EventLoop::runInLoopOOP執行緒AI
- wait() and notify()AI
- 條件佇列大法好:使用wait、notify和notifyAll的正確姿勢佇列AI