Java Thread等待,通知和notifyAll示例

时间:2020-02-23 14:36:57  来源:igfitidea点击:

java中的Object类包含三个最终方法,这些方法允许线程就资源的锁定状态进行通信。
这些方法是wait(),notify()和notifyAll()。
因此,今天我们将研究java程序中的wait,notify和notifyAll。

用Java等待,通知和notifyAll

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

等待

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

通知

notify方法仅唤醒一个正在等待该对象的线程,并且该线程开始执行。
因此,如果有多个线程在等待一个对象,则此方法将仅唤醒其中一个。
唤醒线程的选择取决于线程管理的OS实现。

notifyAll

notifyAll方法唤醒等待对象的所有线程,尽管首先处理哪个线程取决于OS的实现。

这些方法可用于实现生产者消费者问题,其中消费者线程正在等待Queue中的对象,而生产者线程将对象放入队列中并通知正在等待的线程。

让我们看一个示例,其中多个线程在同一个对象上工作,我们使用wait,notify和notifyAll方法。

信息

线程将在其上工作的Java bean类,并调用wait和notify方法。

package com.theitroad.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;
  }

}

服务

该类将等待其他线程调用notify方法以完成其处理。
注意,Waiter线程正在使用同步块在Message对象上拥有监视器。

package com.theitroad.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对象上处理,然后调用notify方法以唤醒等待Message对象的线程的类。
请注意,同步块用于拥有Message对象的监视器。

package com.theitroad.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和Notifier的多个线程并启动它们。

package com.theitroad.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中进行notify和notifyAll。