Java 中Object的wait() notify() notifyAll()方法使用

 更新时间:2017年05月27日 08:40:42   作者:已往之不谏  
这篇文章主要介绍了Java 中Object的wait() notify() notifyAll()方法使用的相关资料,需要的朋友可以参考下

Java 中Object的wait() notify() notifyAll()方法使用

一、前言

  对于并发编程而言,除了Thread以外,对Object对象的wati和notify对象也应该深入了解其用法,虽然知识点不多。

二、线程安全基本知识

  首先应该记住以下基本点,先背下来也无妨:

同一时间一个锁只能被一个线程持有 调用对象的wait()和notify()前必须持有它

三、wait()和notify()理解

3.1 wait()和notify()方法简介

  wait()和notify()都是Object的方法,可以认为任意一个Object都是一种资源(或者资源的一个代表),当多个线程对一个资源进行操作时,如果线程发现这个资源还没有准备好,它就可以在这个资源上进行等待,即调用这个资源的wait()方法,如果有另外的线程经过某些处理觉得这个资源可用了,会调用这个这个资源的notify()方法,告诉等待它的线程,这个资源可以用了。

  当然不使用wait()和notify()方法也是可以的,可以用while()死循环来判断,如下面的伪代码:

class Resource{
  static boolean canUse=false;
}

while(!Resource.canUse){
  //如果不可用,死循环在这里等待
}

//当资源可以使用后,就会跳出循环,往下执行

  这样做是可以,但是特别消耗CPU资源,所以建议用户使用wait()和notify()方法。

3.2 wait()和notify()的价值

  其实从单词意思来看就能看出来,wait就是等待,说明这个资源没有准备好,我要等,还有这一个wait(long timeout) ,表示我只能等待你这么长时间了,过时不候啊,而调用notify()的线程肯定就是对资源进行处理的,处理完进行通知。所以呢,它们就经常用在生产者和消费者模式中。任何涉及等资源到来的情景都适合用这两个方法,

3.3 为什么wait()和notify()必须和synchronized一起使用

  当不在synchronized同步块中使用wait()和notify()或者调用方法的对象不是synchronized的同步锁就会抛异常:

java.lang.IllegalMonitorStateException

  很多人会疑惑为什么必须持有这个对象的锁才能调用对象的wait()和notify()方法呢,我也有这个疑惑,而且我认为这么做是没有必要的。首先看下面的代码:

public class WaitTest{
  // 这是一个资源,模拟的Object
  final NoObjct resource=new NoObjct();
  public static void main(String[] args) throws Exception{
    WaitTest d=new WaitTest();
    d.test();
  }

  public void test() throws Exception{
    Runnable r=new Runnable(){
      public void run(){
        // 调用资源的模拟的wait方法,在方法内部使用synchronized
        resource.noWait();
        System.out.println('线程等待完,执行');
      }
    };
    Thread t=new Thread(r);
    t.start();
    Thread.sleep(2000);
    System.out.println('准备唤醒等待资源的线程');
    // 调用资源的模拟的notify方法,在方法内部使用synchronized
    resource.noNotify();
  }
}

// 因wait()和notify()是final方法,不能覆盖,所以模拟一个Object对象
class NoObjct{
  // 模拟wait方法
  public void noWait(){
    // 这个就相当于将synchronized放到wait方法内部
    synchronized(this){
      try{
        this.wait();
      }catch(InterruptedException e){
        e.printStackTrace();
      }
    }
  }
  // 模拟notify方法
  public void noNotify(){
    // 这个就相当于将synchronized放到notify方法内部
    synchronized(this){
      this.notify();
    }
  }
}

  这是一个简单的wait()和notify()例子,wait等待,notify唤醒。如果忽略掉模拟的Object会发现代码简洁了许多,否则就要每次使用synchronized,如下代码:

public class WaitTest{
  // 这是一个资源,模拟的Object
  final Object resource=new Object();

  public static void main(String[] args) throws Exception{
    WaitTest d=new WaitTest();
    d.test();
  }

  public void test() throws Exception{
    Runnable r=new Runnable(){
      public void run(){
        // 必须使用synchronized
        try{
          synchronized(resource){
            resource.wait();
          }
        }catch(InterruptedException e){
          e.printStackTrace();
        }
        System.out.println('线程等待完,执行');
      }
    };
    Thread t=new Thread(r);
    t.start();

    Thread.sleep(2000);
    System.out.println('准备唤醒等待资源的线程');
    // 必须使用synchronized
    synchronized(resource){
      resource.notify();
    }
  }
}

  所以呢,我觉得wait()和notify()和synchronized一起没有什么意义,毕竟synchronized用来进行代码同步的,和线程之间唤醒没有什么关系(希望有读者能给我相反的意见并说服我)。但是既然这么规定了就必须要去遵守,即必须在synchronized中使用wait和notify,且调用方法的对象必须是同步对象。

四、何时使用wait()和notify()

  在上面已经说了这两个方法的其中一个价值就是用在生产者和消费者模式。但是通过使用它们来构建的生产者和消费者模型很低级而且复杂,完全可以使用BlockingQueue接口的实现类来构建。比如可以使用ArrayBlockingQueue,它既能保证线程安全又能实现阻塞效果,何乐而不为呢。

  除此之外就只有线程间休眠与唤醒了。

     感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!

相关文章

  • Java实现任务超时处理方法

    Java实现任务超时处理方法

    任务超时处理是比较常见的需求,Java中对超时任务的处理有两种方式,在文中给大家详细介绍,本文重点给大家介绍Java实现任务超时处理方法,需要的朋友可以参考下
    2019-06-06
  • java实现图片角度旋转并获得图片信息

    java实现图片角度旋转并获得图片信息

    这篇文章主要为大家详细介绍了java实现图片角度旋转并获得图片信息,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-02-02
  • 微信小程序中的openid的作用详解

    微信小程序中的openid的作用详解

    微信小程序作为连接用户与服务的重要桥梁,在提升用户体验方面发挥着重要作用,本文章将详细探讨openid在微信小程序中的作用及其重要性,帮助开发者更好地理解和利用这一功能,优化应用体验并增强安全性,感兴趣的朋友一起看看吧
    2025-04-04
  • java利用Socket实现聊天室功能实例

    java利用Socket实现聊天室功能实例

    这篇文章主要介绍了java利用Socket实现聊天室功能实例,具有一定的参考价值,感兴趣的小伙伴们可以参考一下。
    2017-02-02
  • IDEA如何将Java项目打包成可执行的Jar包

    IDEA如何将Java项目打包成可执行的Jar包

    在Java开发中,我们通常会将我们的项目打包成可执行的Jar包,以便于在其他环境中部署和运行,本文将介绍如何使用IDEA集成开发环境将Java项目打包成可执行的Jar包,感兴趣的朋友一起看看吧
    2023-07-07
  • java实现学籍管理系统

    java实现学籍管理系统

    这篇文章主要为大家详细介绍了java实现学籍管理系统,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2016-12-12
  • 扩展Hibernate使用自定义数据库连接池的方法

    扩展Hibernate使用自定义数据库连接池的方法

    这篇文章主要介绍了扩展Hibernate使用自定义数据库连接池的方法,涉及Hibernate数据库操作扩展的相关技巧,需要的朋友可以参考下
    2016-03-03
  • 使用Java调用Yolo模型的基本步骤

    使用Java调用Yolo模型的基本步骤

    Yolo(You Only Look Once)是一种基于深度学习的目标检测算法,它可以在一张图像中同时检测出多个目标,并给出它们的位置和类别,这篇文章主要介绍了使用Java调用Yolo模型的基本步骤,需要的朋友可以参考下
    2024-03-03
  • Spring Boot中JSON数值溢出问题从报错到优雅解决办法

    Spring Boot中JSON数值溢出问题从报错到优雅解决办法

    这篇文章主要介绍了Spring Boot中JSON数值溢出问题从报错到优雅的解决办法,通过修改字段类型为Long、添加全局异常处理和数据校验,解决了该问题,文章还提供了类型范围推荐场景和常见问题解答,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2025-04-04
  • Java Swagger使用教程

    Java Swagger使用教程

    Swagger是一个规范和完整的框架,用于生成、描述、调用和可视化 Restful 风格的 Web 服务。总体目标是使客户端和文件系统作为服务器以同样的速度来更新。文件的方法、参数和模型紧密集成到服务器端的代码,允许API来始终保持同步
    2022-07-07

最新评论