本文為翻譯文章,原文地址:http://www./1037/java-thread-wait-notify-and-notifyall-example 在Java的Object類中有三個final的方法允許線程之間進(jìn)行資源對象鎖的通信,他們分別是: wait(), notify() and notifyAll()。 調(diào)用這些方法的當(dāng)前線程必須擁有此對象監(jiān)視器,否則將會報java.lang.IllegalMonitorStateException exception異常。 waitObject的wait方法有三個重載方法,其中一個方法wait() 是無限期(一直)等待,直到其它線程調(diào)用notify或notifyAll方法喚醒當(dāng)前的線程;另外兩個方法wait(long timeout) 和wait(long timeout, int nanos)允許傳入 當(dāng)前線程在被喚醒之前需要等待的時間,timeout為毫秒數(shù),nanos為納秒數(shù)。 notifynotify方法只喚醒一個等待(對象的)線程并使該線程開始執(zhí)行。所以如果有多個線程等待一個對象,這個方法只會喚醒其中一個線程,選擇哪個線程取決于操作系統(tǒng)對多線程管理的實現(xiàn)。 notifyAllnotifyAll 會喚醒所有等待(對象的)線程,盡管哪一個線程將會第一個處理取決于操作系統(tǒng)的實現(xiàn)。 這些方法可以使用于“生產(chǎn)者-消費者”問題,消費者是在隊列中等待對象的線程,生產(chǎn)者是在隊列中釋放對象并通知其他線程的線程。 讓我們來看一個多線程作用于同一個對象的例子,我們使用wait, notify and notifyAll方法。 通過實例來理解Message一個java bean類,線程將會使用它并調(diào)用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; }}
Waiter一個Waiter類,等待其它的線程調(diào)用notify方法以喚醒線程完成處理。注意等待線程必須通過加synchronized同步鎖擁有Message對象的監(jiān)視器。 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()); } }}
Notifier一個Notifier類,處理Message對象并調(diào)用notify方法喚醒等待Message對象的線程。注意synchronized代碼塊被用于持有Message對象的監(jiān)視器。 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一個測試類,交付創(chuàng)建多個等待線程和一個通過線程,并啟動這些線程。 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'); }}
當(dāng)我們調(diào)用以上的代碼時可以看到以下的輸出,但并沒有結(jié)束(完成),因為有兩個線程等待同一個Message對象,但notify()方法只能喚醒一個線程,另一個線程仍然在等待被喚醒。 notify()waiter waiting to get notified at time:1356318734009waiter1 waiting to get notified at time:1356318734010All the threads are startednotifier startedwaiter waiter thread got notified at time:1356318735011waiter processed: notifier Notifying work done 如果我們注釋掉Notifier類中的notify() 方法的調(diào)用,并打開notifyAll() 方法的調(diào)用,將會有以下的輸出信息。 notifyAll()waiter waiting to get notified at time:1356318917118waiter1 waiting to get notified at time:1356318917118All the threads are startednotifier startedwaiter1 waiter thread got notified at time:1356318918120waiter1 processed: notifier Notifying work donewaiter waiter thread got notified at time:1356318918120waiter processed: notifier Notifying work done 一旦notifyAll()方法喚醒所有的Waiter線程,程序?qū)?zhí)行完成并退出。 |
|