Java中的Object类包含三个最终方法,允许线程就资源的锁定状态进行通信。这些方法是`wait()`,`notify()`和`notifyAll()`。所以今天我们将研究Java程序中的`wait`,`notify`和`notifyAll`。
Java中的wait、notify和notifyAll
在任何对象上调用这些方法的当前线程应该具有对象监视器,否则会抛出`java.lang.IllegalMonitorStateException`异常。
wait
Object的wait方法有三个变体,其中一个会无限期地等待,直到其他线程调用对象上的notify或notifyAll方法来唤醒当前线程。另外两个变体会在特定的时间段内使当前线程进入等待状态,然后再唤醒。
notify
通知方法只唤醒在对象上等待的一个线程,然后该线程开始执行。因此,如果有多个线程在等待一个对象,此方法只会唤醒其中一个。唤醒的线程的选择取决于操作系统对线程管理的实现。
notifyAll
notifyAll方法唤醒在对象上等待的所有线程,尽管哪个线程会先处理取决于操作系统的实现。这些方法可以用于实现生产者消费者问题,其中消费者线程等待队列中的对象,而生产者线程将对象放入队列并通知等待的线程。让我们看一个例子,其中多个线程在同一对象上工作,我们使用wait、notify和notifyAll方法。
消息
A java bean class on which threads will work and call wait and notify methods.
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;
}
}
服务员
A class that will wait for other threads to invoke notify methods to complete it’s processing. Notice that Waiter thread is owning monitor on Message object using synchronized block.
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());
//现在处理消息
System.out.println(name+" processed: "+msg.getMsg());
}
}
}
通知器
A class that will process on Message object and then invoke notify method to wake up threads waiting for Message object. Notice that synchronized block is used to own the monitor of Message object.
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
测试类将创建多个等待者和通知器线程,并启动它们。
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() 方法只唤醒其中一个,另一个线程仍然在等待被通知。
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
如果我们注释掉 Notifier 类中的 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() 方法唤醒了所有的 Waiter 线程,并且程序在执行后完成并终止。这就是关于 Java 中等待、通知和notifyAll的全部内容。
Source:
https://www.digitalocean.com/community/tutorials/java-thread-wait-notify-and-notifyall-example