本文为翻译文章,原文地址: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;
}
}
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());
}
}
}
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();
}
}
}
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");
}
}
当我们调用以上的代码时能够看到下面的输出。但并没有结束(完毕),由于有两个线程等待同一个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
假设我们凝视掉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
一旦notifyAll()方法唤醒全部的Waiter线程。程序将会运行完毕并退出。