‍‍

作者 | 东风玖哥,小灰

来源 | 程序员小灰(ID:chengxuyuanxiaohui)

这一次,我们来重点讲解 wait(),notify(),notifyAll() 这三大方法。

// 执行这个方法后,持有此对象监视器的线程会进入等待队列,同时释放锁
// 如果不在synchronized修饰的方法或代码块里调用,则会抛出IllegalMonitorStateException 异常
// 如果当前线程在等待时被中断,则抛出InterruptedException异常
public final void wait() throws InterruptedException {wait(0);
}// timeout是线程等待时间,时间结束则自动唤醒,单位ms
// Java默认的实现方式,native实现
public final native void wait(long timeout) throws InterruptedException;// nanos是更精确的线程等待时间,单位ns(1 ms = 1,000,000 ns)
// Java默认的实现方式
public final void wait(long timeout, int nanos) throws InterruptedException {if (timeout < 0) {throw new IllegalArgumentException("timeout value is negative");}if (nanos < 0 || nanos > 999999) {throw new IllegalArgumentException("nanosecond timeout value out of range");}if (nanos > 0) {timeout++;}wait(timeout);
}

含参数的wait()方法调用以后,线程可以在等待时间结束后被唤醒;无参的wait()方法调用后,则必须等待持有该对象监视器的线程主动调用notify()或notifyAll()方法后才能被唤醒。

两者之间的区别,在于notify()方法唤醒在此对象监视器上等待的单个线程,而notifyAll()方法则唤醒在此对象监视器上等待的所有线程

与wait方法一样,执行notify方法的线程也必须提前获取锁。需要注意的是,被notify方法唤醒的线程并不会立即执行,因为要等调用notify方法的线程释放锁之后才会获取到锁。

有的Java虚拟机(VM)会选择最先调用wait方法的线程,也有的则会随机选择一个线程。尽管notify方法的处理速度比notifyAll方法更快,但使用notifyAll方法更为稳妥。

notify与notifyAll的方法声明如下:

public final native void notify();public final native void notifyAll();

有一家公司开始想要招聘程序员,于是面试了几名候选人:

但公司录用程序员的时间是不确定的,需要综合考虑,无法给出及时反馈。于是告诉他们回去等通知。

经过事后的比较和研究,面试官觉得大黄是招聘的最佳人选,于是让HR小姐姐通知大黄,也就是“唤醒”了大黄:

(1)wait()、notify()和notifyAll()必须在synchronized修饰的方法或代码块中使用。

(2)在while循环里而不是if语句下使用wait(),确保在线程睡眠前后都检查wait()触发的条件(防止虚假唤醒)。

(3)wait()方法必须在多线程共享的对象上调用。

生产者/消费者模型能解决绝大多数并发问题,通过平衡生产线程和消费线程的工作能力,来提高程序的整体处理数据的速度。

生产者线程和消费者线程的处理速度差异,会引起消费者想要获取数据时,数据还没生成或者生产者想要交付数据,却没有消费者接收的问题。对于这样的问题,生产者/消费者模型可以消除这个差异。

首先,按照注意事项(1)和(2)的要求,定义一个生产者,往队列里添加元素:

// 生产者,有详细的注释public class Producer implements Runnable{    private Queue<Integer> queue;    private int maxSize;    public Producer(Queue<Integer> queue, int maxSize){        this.queue = queue;        this.maxSize = maxSize;    }@Override    public void run() {        // 这里为了方便演示做了一个死循环,现实开发中不要这样搞        while (true){            //(1)wait()、notify()和notifyAll()必须在synchronized修饰的方法或代码块中使用            synchronized (queue){                //(2)在while循环里而不是if语句下使用wait(),确保在线程睡眠前后都检查wait()触发的条件(防止虚假唤醒)                while (queue.size() == maxSize){                    try{                        System.out.println("Queue is Full");                        // 生产者线程进入等待状态,在此对象监视器上等待的所有线程(其实只有那个消费者线程)开始争夺锁                        queue.wait();                    }catch (InterruptedException ie){                        ie.printStackTrace();                    }                }                Random random = new Random();                int i = random.nextInt();                System.out.println("Produce " + i);                queue.add(i);                // 唤醒这个Queue对象的等待池中的所有线程(其实只有那个消费者线程),等待获取对象监视器                queue.notifyAll();            }        }    }}

接下来,再定义一个与之类似的消费者类,除了从队列里移除元素的逻辑之外,整体代码大同小异:

// 消费者类
public class Consumer implements Runnable{private Queue<Integer> queue;private int maxSize;public Consumer(Queue<Integer> queue, int maxSize){this.queue = queue;this.maxSize = maxSize;}@Overridepublic void run() {while (true){synchronized (queue){while (queue.isEmpty()){System.out.println("Queue is Empty");try{queue.wait();}catch (InterruptedException ie){ie.printStackTrace();}}int v = queue.remove();System.out.println("Consume " + v);queue.notifyAll();}}}
}

最后编写符合注意事项(3)的测试代码:

public void test(){    //(3)wait()方法必须在多线程共享的对象上调用    // 这个队列就是给消费者、生产者两个线程共享的对象    Queue<Integer> queue = new LinkedList<>();    int maxSize = 5;    Producer p = new Producer(queue, maxSize);    Consumer c = new Consumer(queue, maxSize);    Thread pT = new Thread(p);    Thread pC = new Thread(c);    // 生产者线程启动,获取锁    pT.start();    // 消费者线程启动    pC.start();}

最终的查看运行结果如下:

Produce 1604006010
Produce 1312202442
Produce -1478853208
Produce 1460408111
Produce 1802825495
Queue is Full
Consume 1604006010
Consume 1312202442
Consume -1478853208
Consume 1460408111
Consume 1802825495
Queue is Empty

☞余承东:华为 P50 系列无 5G 版本,但依然流畅
☞IE 退出后,苹果 Safari 成为了开发者最讨厌的浏览器?
☞35 岁程序员的退路:「有人放弃挣扎撤回老家,有人创业失败退回大厂」
☞谷歌程序员犯低级错误?少打一个字符引发重大 Bug,致大量 Chromebook 无法解锁
☞程序员带半箱辣条参加东京奥运,网友:这不是辣条,是狗粮!

漫画:Object 类很大,你忍一下(完结篇)相关推荐

  1. 漫画:Object类很大,你忍一下

    -----  第二天  ----- ------------ 想要了解clone方法的小伙伴,可以看看之前所讲解 原型模式 getClass() getClass方法是干什么的呢?首先,getClas ...

  2. Object类九大方法之getClass方法

    Object类九大方法之getClass方法 https://www.cnblogs.com/wsw-bk/p/8026266.html 获取此Object的运行时类. 什么是运行时类? 在创建对象前 ...

  3. Object类九大方法之notify和notifyAll方法

    Object类九大方法之notify和notifyAll方法 notify()方法表示,当前的线程已经放弃对资源的占有, 通知等待的线程来获得对资源的占有权,但是只有一个线程能够从wait状态中恢复, ...

  4. Object类九大方法之finalize方法

    Object类九大方法之finalize方法 finalize()是Object的protected方法,子类可以覆盖该方法以实现资源清理工作,GC在回收对象之前调用该方法. finalize的作用 ...

  5. Object类九大方法之wait方法

    Object类九大方法之wait方法 wait.notify和notifyAll方法是Object类的final native方法.所以这些方法不能被子类重写,Object类是所有类的超类,因此在程序 ...

  6. 计算机专业的双证在职研究生,计算机类在职研究生最终能获得双证吗难度是不是很大呢...

    在职读研其实优势真的很多,不然也不会每年都有那么多在职者不辞工作的辛苦还有坚持报考,毕竟凭借这份经历可以学习到高端的知识,可以帮助学员提高相应的专业能力,而最终证书的获取也能相应地提升职员在职场的地位 ...

  7. git object 很大_这才是真正的Git——Git内部原理

    本文以一个具体例子结合动图介绍了Git的内部原理,包括Git是什么储存我们的代码和变更历史的.更改一个文件时,Git内部是怎么变化的.Git这样实现的好处等等. TL;DR 本文以一个具体例子结合动图 ...

  8. 云南省高校计算机等级考试c类难吗,A、B、C类的难度差距真的很大吗?

    原标题:A.B.C类的难度差距真的很大吗? 各位考生的职位报好了吗 报好了才发现还分A.B.C类 你辛苦的备考真的对症下药了吗 先来了解一下怎么确定自己是哪一类 以2018年江苏公务员考试职位表为例, ...

  9. JAVA-初步认识-第十一章-object类-equals方法覆盖

    一. 现在要谈论equals方法另一个方面.如果不写equals方法,直接用==来比较也是可以的,貌似equals方法有点多余. 现在不比较对象是否相等,而是比较对象中的特定内容,比如说对象的年龄,之 ...

最新文章

  1. 交叉验证分析每一折(fold of Kfold)验证数据的评估指标并绘制综合ROC曲线
  2. Java Decimal范围_Java BigDecimal初探
  3. 间接银团贷款(Indirectly Syndicated Loan/PARTICIPATED)
  4. 无基础人员转行做机器学习可以吗?
  5. 一套cms内容网站发布系统
  6. 云ERP系统如何进行流程设计
  7. 二次重建基本完成辣!
  8. java hessian rmi_RMI,socket,rpc,hessian,http比较
  9. vue获取tr内td里面所有内容_vue 项目学习
  10. android百度导航实现,Android 集成百度地图实现设备定位
  11. 使用Angular与TypeScript构建Electron应用(二)
  12. ~~遗传算法最最最最简单的实例~~
  13. 京东订单系统高可用架构及演变过程
  14. c语言tc游戏代码大全,wintcC语言小游戏画图代码.doc
  15. UI 即 User Interface( 用户界面 ) 的简称
  16. 这个行业一半人月薪超过8千!
  17. 数字IC设计工程师笔试面试经典100题
  18. 超详细的文件上传和下载(Spring Boot)
  19. Java学习之路-----Java基础简介,基础语法,Java标识符,修饰符,关键字与注释
  20. 闭关修炼(十)单例设计

热门文章

  1. 被小扎誉为整个科技界的愿景,元宇宙到底是什么?
  2. 吴恩达,45岁生日快乐!提出著名二八定律:80%数据+20%模型=更好的AI
  3. 【实习内推】2020腾讯产品暑期实习招聘
  4. 北师大刘嘉:认知神经科学如何打开 AI 黑箱?
  5. 机器学习的中流砥柱:用于模型构建的基础架构工具有哪些?
  6. 调查报告:工人们并不担心将来会被AI取代
  7. 4句话让你明白什么是AI
  8. SAP LSMW 物料主数据导入毛重净重放大1000倍问题之对策
  9. 刚刚,2021年诺贝尔生理学或医学奖揭晓!
  10. 张钹院士:制约人工智能发展的最大困难是什么?