原文地址:http://www.journaldev.com/1037/java-thread-wait-notify-and-notifyall-example
Java的Object類提供了三個final方法來在維護多線程中資源的鎖狀態。它們是wait(), notify() 和 notifyAll()。使用這三個方法來維護資源的線程必須有該資源的monitor(使用synchronized關鍵字,譯者注),否則會拋出java.lang.IllegalMonitorStateException.
wait
對象的wait方法有三種調用方式,第一種當前線程會無限等待其他線程調用該對象的notify或者notifyAll方法來喚醒它所在的線程;另外兩個會令當前線程等待特定的時間然後喚醒。
notify
notify方法每次只喚醒一個等待該object的線程。所以如果多個線程在等待這個object,這個方法只會喚醒其中的一個。喚醒哪個取決於系統實現的線程管理器。
notifyAll
notifyAll方法喚醒等待該object的所有線程,哪個先喚醒取決於操作系統。
這些方法可以用來實現 producer-consumer-problem (生產者消費者問題),消費者線程等待隊列中的對象,生產者線程向隊列中放入對象並通知等待的線程。
讓我們看一個多線程操作同一個對象的例子。
Message
下面是一個java bean類,線程會調用這個類的wait和notify方法。
Message.java
package com.journaldev.concurrency;
public class Message {
private String msg;
public Message(String str){
this.msg=str;
}
public String getMsg() {
returnmsg;
}
public void setMsg(String str) {
this.msg=str;
}
}
Waiter
該類會等待別的線程調用notify方法來喚醒自己。注意Waiter線程使用synchronized 塊擁有了Message的monitor。
package com.journaldev.concurrency;
public class Waiter implements Runnable{
private Message msg;
public Waiter(Message m){
this.msg=m;
}
@Override
publicvoidrun() {
String name = Thread.currentThread().getName();
synchronized(msg) {
try{
System.out.println(name+" waiting to get notified at time:"+System.currentTimeMillis());
msg.wait();
}catch(InterruptedException e){
e.printStackTrace();
}
System.out.println(name+" waiter thread got notified at time:"+System.currentTimeMillis());
//process the message now
System.out.println(name+" processed: "+msg.getMsg());
}
}
}
Notifier
該類會對Message對象進行處理,然後調用notify方法來喚醒等待Message對象的線程。它同樣用synchronized塊擁有了對Message的管理。
Notifier.java
package com.journaldev.concurrency;
public class Notifier implements Runnable {
private Message msg;
public Notifier(Message msg) {
this.msg = msg;
}
@Override
public void run() {
String name = Thread.currentThread().getName();
System.out.println(name+" started");
try{
Thread.sleep(1000);
synchronized(msg) {
msg.setMsg(name+" Notifier work done");
msg.notify();
// msg.notifyAll();
}
} catch(InterruptedException e) {
e.printStackTrace();
}
}
}
WaitNotifyTest
該類會創建並運行多個Waiter線程和一個Notifer線程。
WaitNotifyTest.java
package com.journaldev.concurrency;
public class WaitNotifyTest {
public static void main(String[] args) {
Message msg = newMessage("process it");
Waiter waiter = new Waiter(msg);
new Thread(waiter,"waiter").start();
Waiter waiter1 = new Waiter(msg);
new Thread(waiter1, "waiter1").start();
Notifier notifier = new Notifier(msg);
new Thread(notifier, "notifier").start();
System.out.println("All the threads are started");
}
}
運行上面的程序,會看到下面的運行結果,程序不會結束因爲有兩個線程在等待Message對象但是notify方法只會喚醒其中的一個,另外一個依然在等待被喚醒。
waiter waiting to get notified at time:1356318734009
waiter1 waiting to get notified at time:1356318734010
All the threads are started
notifier started
waiter waiter thread got notified at time:1356318735011
waiter processed: notifier Notifier work done
註釋掉notify(),使用notifyAll()方法,會出現下面的運行結果。
waiter waiting to get notified at time:1356318917118
waiter1 waiting to get notified at time:1356318917118
All the threads are started
notifier started
waiter1 waiter thread got notified at time:1356318918120
waiter1 processed: notifier Notifier work done
waiter waiter thread got notified at time:1356318918120
waiter processed: notifier Notifier work done
notifyAll喚醒了所有的等待線程,程序結束。
譯者注:
1 有哪些更實際的例子呢?