Java 线程 wait、notify 和 notifyAll 示例
Java 中的 Object 类包含三个 final 方法,允许线程就资源的锁定状态进行通信。这些方法是wait()、notify()和notifyAll()。所以今天我们将研究 Java 程序中的 wait、notify 和 notifyAll。
Java 中的 wait、notify 和 notifyAll
在任何对象上调用这些方法的当前线程都应该具有对象监视器,否则它会抛出java.lang.IllegalMonitorStateException异常。
等待
对象等待方法有三种变体,一种是无限期地等待任何其他线程调用对象上的notify或notifyAll方法来唤醒当前线程。其他两种变体将当前线程置于等待特定时间后再唤醒的状态。
通知
通知方法只会唤醒一个等待该对象的线程,并且该线程会开始执行。因此,如果有多个线程在等待一个对象,此方法只会唤醒其中一个线程。唤醒哪个线程取决于操作系统对线程管理的实现。
通知全部
notifyAll 方法唤醒所有等待该对象的线程,但首先处理哪个线程取决于操作系统实现。这些方法可用于实现生产者消费者问题,其中消费者线程正在等待队列中的对象,生产者线程将对象放入队列并通知等待线程。让我们看一个例子,其中多个线程在同一个对象上工作,我们使用 wait、notify 和 notifyAll 方法。
信息
线程将在其上工作并调用等待和通知方法的 Java bean 类。
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 线程使用同步块拥有对 Message 对象的监视器。
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());
}
}
}
通知程序
一个处理 Message 对象的类,然后调用通知方法来唤醒等待 Message 对象的线程。请注意,同步块用于拥有 Message 对象的监视器。
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();
}
}
}
等待通知测试
测试类将创建多个 Waiter 和 Notifier 线程并启动它们。
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");
}
}
当我们调用上述程序时,我们将看到下面的输出,但程序不会完成,因为有两个线程在等待消息对象,而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中wait、notify和notifyAll的全部内容。