等待/通知机制 notify() 、notifyAll()、wait()使用

   等待/通知机制: 类似于生产者与消费者的关系。是指一个线程A调用了对象Object的wait()方法进入等待状态。另一个线程B调用notify()或notifyAll()方法,通知进入等待的线程。线程A收到通知后,从等待中返回,继续执行后面的操作。

一. 方法解释说明

1. wait() 方法

在这里插入图片描述

wait
public final void wait()  throws InterruptedException
	在其他线程调用此对象的 notify() 方法或 notifyAll() 方法前,导致当前线程等待。换句话说,此方法的
行为就好像它仅执行 wait(0) 调用一样。
	当前线程必须拥有此对象监视器。该线程发布对此监视器的所有权并等待,直到其他线程通过调用 notify 
方法,或 notifyAll 方法通知在此对象的监视器上等待的线程醒来。然后该线程将等到重新获得对监视器的所有
权后才能继续执行。
	对于某一个参数的版本,实现中断和虚假唤醒是可能的,而且此方法应始终在循环中使用:
synchronized (obj) {
	while (<condition does not hold>)
		obj.wait();
		... // Perform action appropriate to condition
}

   从JDK的官方文档中可以得出:
      1. 当前线程必须拥有此对象监视器(监视器在下面解释);
      2. 其他线程通过调用 notify 方法,或 notifyAll 方法通知在此对象的监视器上等待的线程才会醒来;
      3. 该线程将等到重新获得对监视器的所有权后才能继续执行(重新获取锁);
      4. 此方法应始终在循环中使用(因为需要等待被通知唤醒);

2. notify()方法

在这里插入图片描述
  唤醒在此对象监视器上等待的单个线程。如果所有线程都在此对象上等待,则会选择唤醒其中一个线程。选择是任意性的,并在对实现做出决定时发生。

   This method should only be called by a thread that is the owner of this object’s monitor. A thread becomes the owner of the object’s monitor in one of three ways:
   此方法只应由作为此对象监视器的所有者的线程来调用。通过以下三种方法之一,线程可以成为此对象监视器的所有者:
   1. By executing a synchronized instance method of that object.
   2. By executing the body of a {@code synchronized} statement that synchronizes on the object.
   3. For objects of type {@code Class,} by executing a synchronized static method of that class.
   介绍完方法和Demo后在介绍监视器,晦涩难懂,在博客的尾部查看。

3. notifyAll()方法

在这里插入图片描述
   唤醒在此对象监视器上等待的所有线程。

二. 三种方法的使用

   此案例是一个快递业务,当送货的地点发生变化的时候,通知送货员

public class Express {

	 public static final String CITY = "Hongkong";
	//地点
	 private String place = CITY;
	 /** 改变地址*/
	 public synchronized void changePlace(String place){
	     this.place = place;
	     notify();
	 }
	 /**地址改变做出响应*/
	 public synchronized void changePlaceResponse(){
	     while (this.place.equals(CITY)){
	         try {
	             wait();
	             System.out.println("thread :" + Thread.currentThread().getName() +", Change of place");
	         } catch (InterruptedException e) {
	             //Todo
	         }
	     }
	     System.out.println("thread :" + Thread.currentThread().getName() +", deal place: " + place +" call delivery");
	 }
	
	 static Express express = new Express();
	
	 public static void main(String[] args) throws InterruptedException {
	     for (int i = 0; i < 3; i++) {
	         new ThreadPlace().start();
	     }
	     Thread.sleep(1000);
	     express.changePlace("Beijing");
	     System.out.println("main thread over");
	 }
	
	 private static class ThreadPlace extends Thread{
	     @Override
	     public void run() {
	         express.changePlaceResponse();
	     }
	 }
}

此时只有一个线程被唤醒:
在这里插入图片描述
修改 notify();–> notifyAll(); 3个线程都被唤醒:
在这里插入图片描述

三. 监视器的理解

   我们知道synchronized 用在方法上,与synchronized(this)等价,this可以省略。因此我们这样写并不会有什么问题。可是还是看不出监视器是什么,是怎么监视的。接下来我们修改等待和通知的方法进行测试。

public void changePlace(String place){
	  synchronized(this){
	           this.place = place;
	           notifyAll();
      }
   }

   测试的结果是正常的。继续测试,修改changePlace中synchronized锁的对象:
在这里插入图片描述
   似乎是这四个对象必须是同一个,才能起到监视的作用。是这样的吗?按照上面的推论,继续测试:

 public void changePlace(String place){
    synchronized(this.place){
           this.place = place;
           this.place.notifyAll();
       }
   }
   /**地址改变做出响应*/
   public void changePlaceResponse(){
       synchronized(this.place){
           while (this.place.equals(CITY)){
               try {
                   this.place.wait();
                   System.out.println("thread :" + Thread.currentThread().getName() +", Change of place");
               } catch (InterruptedException e) {
                   //Todo
               }
           }
           System.out.println("thread :" + Thread.currentThread().getName() +", deal place: " + place +" call delivery");
       }
   }

   发现什么问题了吗?感觉看起来这四个对象都是同一个,没有问题。运行一把:
在这里插入图片描述
   结果仍然报了这个异常,难道刚刚的推论错了?!仔细分析发现this.place 的值已经被改变了,那吧18行与19行进行调换试下。果然有运行正常了。然后继续换其他的组合尝试,都没问题,屡试不爽。
   总结: synchronized锁的对象与调用wait()等待和notify() /notifyAll() 通知的对象需保持一致!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值