原文地址: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 有哪些更实际的例子呢?