java notify唤醒原理_Java wait和notify虚假唤醒原理

自己在此记录一下,方便日后复习。

虚假唤醒的概念

jdk官方文档解释:

3q02d532yca.jpg

所以说在wait和notify一块使用时,如果使用if作为条件时,会有虚假唤醒的情况发生,所以必须使用while作为循环条件。下面来举例实验:

首先,创建一个资源类:(在多线程中,一般都是资源类和线程操作解耦,不放在用同一个类中,只有在线程操作资源类时,才会创建资源类的对象)

package com.test;

/**

* 资源类

* @author Huxudong

* @createTime 2020-04-01 21:57:39

**/

public class Resource {

/** 产品数 */

private int product = 0;

/** 进货 */

public synchronized void get() {

if(product >= 10) {

System.out.println(Thread.currentThread().getName()+":"+"产品已满!");

/** 当商品已经满的时候,进货线程挂起 */

try {

this.wait();

} catch (InterruptedException e) {

e.printStackTrace();

}

}

/** 进货 */

System.out.println(Thread.currentThread().getName()+":"+ ++product);

/** 唤醒其他线程 */

this.notifyAll();

}

/** 售货 */

public synchronized void sale() {

if(product <= 0) {

System.out.println(Thread.currentThread().getName()+":"+"产品已空");

try {

this.wait();

} catch (InterruptedException e) {

e.printStackTrace();

}

}

/** 售货 */

System.out.println(Thread.currentThread().getName()+":"+ --product);

/** 唤醒其他线程 */

this.notify();

}

}

然后再创建线程来操作我们的资源类(通过java8新特性Lambda表达式直接创建)

package com.test;

import java.util.concurrent.TimeUnit;

/**

* 线程操作资源类,实现线程与资源类的解耦合

* @author Huxudong

* @createTime 2020-04-01 23:13:54

**/

public class TestPc {

public static void main(String[] args) {

Resource resource = new Resource();

new Thread(()->{

for (int i = 0; i < 20; i++) {

try {

/** 睡眠,便于观察结果 */

TimeUnit.SECONDS.sleep(2);

} catch (InterruptedException e) {

e.printStackTrace();

}

resource.get();

}

},"生产者A").start();

new Thread(()->{

for (int i = 0; i < 20; i++) {

resource.sale();

}

},"消费者C").start();

new Thread(()->{

for (int i = 0; i < 20; i++) {

resource.get();

}

},"生产者B").start();

new Thread(()->{

for (int i = 0; i < 20; i++) {

resource.sale();

}

},"消费者D").start();

}

}

先来看看如果使用if条件会发生什么:

e5ed96fa20ba74a04a21c25b69c2b390.png

对,你没看错,怎么可能会出现负数呢,这肯定是不对的。冷静下来分析一下,还是有点头绪,知道哪里出现了问题的(那你是一个处事不惊的人,很厉害)。

来,分析一下,一开始先调用了消费者C,D线程(因为我们写了睡眠在生产者中),消费者此时发现此时product资源为0,所以,消费者C,D这两个兄弟,没办法只能调用wait方法,睡眠了,并且释放了锁。

但是此时第一个消费者已经苏醒了,发动机开始生产产品了,并且生产之后,又唤醒了所有等待的消费者线程。这消费者C,D两兄弟终于苏醒了,D哥们先获得了锁,所以就先消费了一个产品,然后就又发现没有产品了,又伤心的休眠去了,但是不要忘了,此时还有一个C哥们被唤醒了啊,你唤醒了人家,人家总的干点什么事情吧,不然这多难受,刚好不巧的是,此时的判断条件是if,所以此时C哥们便不受条件的约束,接着上面自己睡眠的代码处执行,毅然决然的又去消费了一个产品,原来D哥们消费后,就已经为0了,这个C哥们再去消费减一,不就是-1了吗,以此类推分析。发现如果判断条件用不好,此时唤醒的C哥们就相当于虚假唤醒的了,会给程序带来不可预估的错误。所以在这里判断必须要使用while,先来看看把if换成while的结果。

42oknqsgx3b.jpg

这回结果就比较正常了,为什么使用while就可以呢,因为像上文所说,即使唤醒了所有的消费者线程,此时会不停while循环判断,如果此时条件是为0,那么C哥们就不能出while,那么他也就不回执行下面消费产品的减减操作了,那么就会避免了这种错误。这也是官方提倡的在使用wait 和notifyAll的时候,必须使用while循环条件判断。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持聚米学院。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/541020.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C#里面的三种定时计时器:Timer

在.NET中有三种计时器&#xff1a;1、System.Windows.Forms命名空间下的Timer控件&#xff0c;它直接继承自Componet。Timer控件只有绑定了Tick事件和设置EnabledTrue后才会自动计时&#xff0c;停止计时可以用Stop()方法控制&#xff0c;通过Stop()停止之后&#xff0c;如果想…

wireshark rto_RTO的完整形式是什么?

wireshark rtoRTO&#xff1a;地区运输办公室/公路运输办公室 (RTO: Regional Transport Office/ Road Transport Office) RTO is an abbreviation of the Regional Transport Office. It is an Indian Government departmental organization that is responsible for upholdin…

java8 json转xml_2019-08-17java对象与json,xml互转

依赖的jar包&#xff0c;jackson-all-1.7.6.jar,xstream-1.4.4.jar下载地址:链接&#xff1a;https://pan.baidu.com/s/1LflD135qlQiIPGXw5XwDmw提取码&#xff1a;6v29复制这段内容后打开百度网盘手机App&#xff0c;操作更方便哦package json_xml;import com.thoughtworks.xs…

10.8-全栈Java笔记:序列化/反序列化的步骤和实例

本节我们详细讲解10.3节中提到的序列化和反序列化操作。序列化和反序列化是什么当两个进程远程通信时&#xff0c;彼此可以发送各种类型的数据。 无论是何种类型的数据&#xff0c;都会以二进制序列的形式在网络上传送。比如&#xff0c;我们可以通过http协议发送字符串信息&am…

有效的网络推广超级实用方法

我叫龙雨&#xff0c;先后在百度搜狗工作过3年&#xff0c;后来一直负责一家公司的的网络营销!不知道大家有没有听过111>3这样一个概念&#xff0c;简单来说一下这概念!第一呢就是自己的资源&#xff0c;把自己的资源维护好开发好;第二就是网络营销&#xff0c;网络营销利用…

什么为java运行时的环境_什么是JRE?Java运行时环境简介(一)

Java开发工具包(JDK),Java虚拟机(JVM)和Java运行时环境(JRE)共同构成了用于开发和运行Java应用程序的Java平台组件的强大功能.实际上,运行时环境是一种旨在运行其他软件的软件.作为Java的运行时环境,JRE包含Java类库,Java类加载器和Java虚拟机.在这个系统中:的类加载器是负责正…

c语言atoll函数怎么用_C ++中带有示例的atoll()函数

c语言atoll函数怎么用C Atoll()函数 (C atoll() function) atoll() function is a library function of cstdlib header. It is used to convert the given string value to the integer value. It accepts a string containing an integer (integral) number and returns its…

看清美国“黑客帝国”的真面目

“维基揭秘”网站近日发布了近9000份据称属于美国中央情报局的机密文件&#xff0c;显示中情局拥有强大的黑客攻击能力&#xff0c;秘密侵入了手机、电脑、智能电视等众多智能设备。继美国国家安全局承包商前雇员斯诺登曝光国安局“棱镜”等监控计划之后&#xff0c;此次曝光再…

python 示例_带有示例的Python File close()方法

python 示例文件close()方法 (File close() Method) close() method is an inbuilt method in Python, it is used to flush and close the IO object (file). If we close a closed file it has no effect. close()方法是Python中的内置方法&#xff0c;用于刷新和关闭IO对象(…

linux上mysql分区磁盘位置_Linux下Oracle软件、数据文件等所在的磁盘分区空间不足的解决思路...

虚拟机中的ORACLE运行的久了&#xff0c;归档、数据文件不断增长&#xff0c;原来安装ORACLE的分区空间不足。此时可以重新向虚拟机增加一块硬盘&#xff0c;将OR虚拟机中的Oracle运行的久了&#xff0c;归档、数据文件不断增长&#xff0c;原来安装ORACLE的分区空间不足。此时…

FloatingActionMenu 向上弹出菜单

本人在github上找到了一个FloatingActionsMenu,精简了其效果&#xff08;原效果有上下左右四个方向&#xff09;仅仅保留向上的效果&#xff0c;并做了一定的优化。github上的源代码&#xff1a;地址 &#xff0c;精简后的源代码地址:源代码地址。 转载于:https://www.cnblogs.…

java uuid静态方法_Java UUID的variant()方法和示例

java uuid静态方法UUID类variant()方法 (UUID Class variant() method) variant() method is available in java.util package. variant()方法在java.util包中可用。 variant() method is used to get the variant number linked with this UUID. variant()方法用于获取与此UUI…

java程序服务不能启动不了_JavaService.exe注册的windows服务无法启动问题

最近开发了个java程序&#xff0c;打成 jar 包想要在windows后台运行&#xff0c;于是使用JavaService.exe进行windows服务注册&#xff0c;服务注册很成功&#xff0c;但是在启动时显示“服务无法启动”&#xff0c;为此耗费了大量的时间与精力&#xff0c;终于发现问题所在&a…

给孩子一束安全的光 明基WiT MindDuo亲子共读灯首发评测

论一束光的重要性你该听听一个高度近视孩子的自述&#xff0c;论童年陪伴的重要性你该听听一个留守儿童的自述&#xff0c;改善孩子童年的全球第一盏亲子共读台灯&#xff0c;贴合孩子与家长的心灵&#xff0c;量身打造每一种情境的光线去感受孩子成长学习过程 一个高度近视眼孩…

Java Scanner next()方法与示例

扫描仪类的next()方法 (Scanner Class next() method) Syntax: 句法&#xff1a; public String next();public String next(Pattern patt);public String next(String patt);next() method is available in java.util package. next()方法在java.util包中可用。 next() metho…

mysql怎样查表的模式_mysql常用基础操作语法(四)--对数据的简单无条件查询及库和表查询【命令行模式】...

1、mysql简单的查询&#xff1a;select 字段1&#xff0c;字段2... from tablename;如果字段那里写一个*&#xff0c;代表查询所有的字段&#xff0c;等同于指定出所有的字段名&#xff0c;因此如果要查询所有字段的数据&#xff0c;一般都是用*。2、去重查询&#xff1a;selec…

Google再次从官方商店下架伪装成合法程序的恶意应用

本月内的第二次&#xff0c;Google 从官方应用商店 Google Play 移除了伪装成合法程序的恶意应用。被移除的应用都属于名叫 Ztorg 的 Android 恶意程序家族&#xff0c;能利用已知的漏洞 root 被感染的设备&#xff0c;使其很难被删除。自去年 9 月以来&#xff0c;Ztorg 恶意应…

java scanner_Java Scanner skip()方法与示例

java scanner扫描仪类skip()方法 (Scanner Class skip() method) Syntax: 句法&#xff1a; public Scanner skip(Pattern patt);public Scanner skip(String patt);skip() method is available in java.util package. skip()方法在java.util包中可用。 skip(Pattern patt) me…

MySQL文件后_MySQL误删除文件后,如何恢复

MySQL在运行中&#xff0c;如果误删除数据文件&#xff0c;只有服务进程没有退出&#xff0c;那么就有办法将其恢复。首先介绍Linux下lsof&#xff1a;他可以显示打开的文件和网络连接。其次/proc目录包含了反映内核和进程树的各种文件。/proc/504目录包含的是PID是504的进程信…

【载誉】致远互联荣获“2017最佳协同管理解决方案”殊荣

6月15日&#xff0c;一年一度的大连软交会于大连市世界博览广场盛大举行。“2017企业服务创新论坛”作为软交会最重要的组成部分之一&#xff0c;本年度以“守正出新——通往基业长青的数字化选择”为主题&#xff0c;吸引到近200位企业级服务领域的企业家及高管参加。致远互联…