原文:http://blog.csdn.net/luoweifu/article/details/46664809 講得很透徹,留檔學習。
本文爲翻譯文章,原文地址:http://www.journaldev.com/1037/java-thread-wait-notify-and-notifyall-example
在Java的Object類中有三個final的方法允許線程之間進行資源對象鎖的通信,他們分別是: wait(), notify() and notifyAll()。
調用這些方法的當前線程必須擁有此對象監視器,否則將會報java.lang.IllegalMonitorStateException exception異常。
wait
Object的wait方法有三個重載方法,其中一個方法wait() 是無限期(一直)等待,直到其它線程調用notify或notifyAll方法喚醒當前的線程;另外兩個方法wait(long timeout) 和wait(long timeout, int nanos)允許傳入 當前線程在被喚醒之前需要等待的時間,timeout爲毫秒數,nanos爲納秒數。
notify
notify方法只喚醒一個等待(對象的)線程並使該線程開始執行。所以如果有多個線程等待一個對象,這個方法只會喚醒其中一個線程,選擇哪個線程取決於操作系統對多線程管理的實現。
notifyAll
notifyAll 會喚醒所有等待(對象的)線程,儘管哪一個線程將會第一個處理取決於操作系統的實現。
這些方法可以使用於“生產者-消費者”問題,消費者是在隊列中等待對象的線程,生產者是在隊列中釋放對象並通知其他線程的線程。
讓我們來看一個多線程作用於同一個對象的例子,我們使用wait, notify and notifyAll方法。
通過實例來理解
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() {
return msg;
}
public void setMsg(String str) {
this.msg=str;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
Waiter
一個Waiter類,等待其它的線程調用notify方法以喚醒線程完成處理。注意等待線程必須通過加synchronized同步鎖擁有Message對象的監視器。
Waiter.java
package com.journaldev.concurrency;
public class Waiter implements Runnable{
private Message msg;
public Waiter(Message m){
this.msg=m;
}
@Override
public void run() {
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());
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
Notifier
一個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();
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
WaitNotifyTest
一個測試類,交付創建多個等待線程和一個通過線程,並啓動這些線程。
WaitNotifyTest.java
package com.journaldev.concurrency;
public class WaitNotifyTest {
public static void main(String[] args) {
Message msg = new Message("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");
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
當我們調用以上的代碼時可以看到以下的輸出,但並沒有結束(完成),因爲有兩個線程等待同一個Message對象,但notify()方法只能喚醒一個線程,另一個線程仍然在等待被喚醒。
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 Notifying work done
- 1
- 2
- 3
- 4
- 5
- 6
- 7
如果我們註釋掉Notifier類中的notify() 方法的調用,並打開notifyAll() 方法的調用,將會有以下的輸出信息。
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 Notifying work done
waiter waiter thread got notified at time:1356318918120
waiter processed: notifier Notifying work done
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
一旦notifyAll()方法喚醒所有的Waiter線程,程序將會執行完成並退出。
- 本文已收錄於以下專欄:
- 編程思想