天天看点

Java 线程wait、notify和notifyAll

作者:农非农

Java 中的 Object 类包含三个最终方法,这些方法允许线程就资源的锁定状态进行通信。这些方法是wait(),notify()和notifyAll()。

wait、notify和notifyAll

Java 线程wait、notify和notifyAll

在任何对象上调用这些方法的当前线程应该具有对象监视器,否则它会抛出java.lang.IllegalMonitorStateException异常。

wait

对象等待方法有三种差异,一种是无限期地等待对象上的任何其他线程调用 notify 或 notifyAll 方法来唤醒当前线程。其他两个差异使当前线程在唤醒之前等待特定的时间量。

notify

通知方法仅唤醒一个等待对象的线程,该线程开始执行。因此,如果有多个线程在等待一个对象,则此方法将仅唤醒其中一个线程。选择要唤醒的线程取决于线程管理的操作系统实现。

notifyAll

notifyAll 方法唤醒等待对象的所有线程,尽管哪个线程将首先处理取决于操作系统实现。这些方法可用于实现生产者使用者问题,其中使用者线程正在等待队列中的对象,生产者线程将对象放入队列中并通知等待的线程。让我们看一个示例,其中多个线程在同一个对象上工作,我们使用 wait、notify 和 notifyAll 方法。

Message

一个 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

一个类,它将等待其他线程调用通知方法以完成其处理。请注意,Waiter 线程在使用同步块的消息对象上拥有监视器。

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

一个类,它将在 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();
          }  
      }
}
           

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中。

继续阅读