JUC虚假唤醒(六)
为什么条件锁会产生虚假唤醒现象(spurious wakeup)?
在不同的语言,甚至不同的操作系统上,条件锁都会产生虚假唤醒现象。所有语言的条件锁库都推荐用户把wait()放进循环里:
while (!cond) {
lock.wait();
}
这个一般出现在多线程竞争的时候,when no thread specifically broadcast or signaled that condition variable,也就是没有线程这时候释放锁信号,但是wait也会又返回。(看起来这个属于线程的系统问题,属于几率问题)
如果你采用if的形式的话,就直接往下跑了。
if (!cond) {
lock.wait();
}
产生了虚假唤醒图示说明:

程序说明:
(1)product <= 0时,两个消费者先后根据if条件判断为“缺货”,都进入wait状态;
(2)另外一个生产者生产了产品之后,通过this.notifyAll();的调用,唤醒了所有的消费线程。使得他们共同执行--produce的操作;也就是说,
--product; // 被执行了两次
但是如果你采用while,他会判别你的锁条件标志还没有被修改,那么会再一次的进入到await的状态中。
这个问题其实很好理解
从wait函数中返回的条件有二,根据顺序为
A,从挂起状态中被唤醒
B,获得cond的锁
如果条件变量被notify,有多个线程同时同时从挂起状态中被唤醒,此时他们会争夺cond的锁。
第一个成功获得锁的线程在临界区中读取cond,并决定是继续wait,还是执行他的工作,选择后者可能会修改cond的状态。
因此,后续获得锁的线程必须确认前面的线程是否修改了cond。notify_one和notify_all,分别对应所有的线程都在等同一个cond或存在多个cond关联到同一个条件变量上。与try_lock不同,条件变量很好地解决了线程的等待问题,不用频繁地争夺锁。
wait, notify, notifyAll 方法说明:
- wait:在其他线程调用此对象的 notify()方法或notifyAll()方法前,导致当前线程等待。当前线程必须拥有此对象监视器。该线程发布对此监视器的所有权并等待,直到其他线程通过调用notify方法,或 notifyAll方法通知在此对象的监视器上等待的线程醒来。然后该线程将等到重新获得对监视器的所有权后才能继续执行。
- notify:唤醒在此对象监视器上等待的单个线程,直到当前线程放弃此对象上的锁定,才能继续执行被唤醒的线程。如果所有线程都在此对象上等待,则会选择唤醒其中一个线程,选择是任意性的,被唤醒的线程将以常规方式与在该对象上主动同步的其他所有线程进行竞争。
- notifyAll:唤醒在此对象监视器上等待的所有线程,直到当前线程放弃此对象上的锁定,才能继续执行被唤醒的线程。被唤醒的线程将以常规方式与在该对象上主动同步的其他所有线程进行竞争。
参考链接
本文主要整理自互联网,主要是便于自己复习知识所用,侵权联系删除,以下为原文参考链接!
【1】为什么条件锁会产生虚假唤醒现象(spurious wakeup)?
【2】JUC 源码分析 四 wait notify notifyAll 与 条件对象
JUC虚假唤醒(六)的更多相关文章
- (三)juc高级特性——虚假唤醒 / Condition / 按序交替 / ReadWriteLock / 线程八锁
8. 生产者消费者案例-虚假唤醒 参考下面生产者消费者案例: /* * 生产者和消费者案例 */ public class TestProductorAndConsumer { public stat ...
- 7.JUC线程高级-生产消费问题&虚假唤醒
描述 生产消费问题在java多线程的学习中是经常遇到的问题 ,多个线程共享通一个资源的时候会出现各种多线程中经常出现的各种问题. 实例说明 三个类:售货员Clerk,工厂Factory,消费者Cons ...
- java多线程 生产者消费者案例-虚假唤醒
package com.java.juc; public class TestProductAndConsumer { public static void main(String[] args) { ...
- java多线程之消费生产模型-使用synchronized解决虚假唤醒
package com.wenshao.juc; /** * 生产者和消费者案例 * * @author Administrator * */ public class TestProductorAn ...
- Java并发编程虚假唤醒问题(生产者和消费者关系)
何为虚假唤醒: 当一个条件满足时,很多线程都被唤醒了,但是只有其中部分是有用的唤醒,其它的唤醒都是无用功:比如买货:如果商品本来没有货物,突然进了一件商品,这是所有的线程都被唤醒了,但是只能一个人买, ...
- notify丢失、虚假唤醒
notify丢失: 假设线程A因为某种条件在条件队列中等待,同时线程B因为另外一种条件在同一个条件队列中等待,也就是说线程A/B都被同一个Object.wait()挂起,但是等待的条件不同. 现在假设 ...
- pthread_cond_wait虚假唤醒
pthread_cond_wait中的while()不仅仅在等待条件变量前检查条件cond_is_false是否成立,实际上在等待条件变量后也检查条件cond_is_false是否成立.在多线程等待的 ...
- Java-JUC(八):使用wait,notify|notifyAll完成生产者消费者通信,虚假唤醒(Spurious Wakeups)问题出现场景,及问题解决方案。
模拟通过线程实现消费者和订阅者模式: 首先,定义一个店员:店员包含进货.卖货方法:其次,定义一个生产者,生产者负责给店员生产产品:再者,定义一个消费者,消费者负责从店员那里消费产品. 店员: /** ...
- 多线程编程中条件变量和的spurious wakeup 虚假唤醒
1. 概述 条件变量(condition variable)是利用共享的变量进行线程之间同步的一种机制.典型的场景包括生产者-消费者模型,线程池实现等. 对条件变量的使用包括两个动作: 1) 线程等待 ...
随机推荐
- Pycharm+Python3+python工程打包成exe+在windows下自动定时运行
python3打包成exe---pyinstaller方法:https://www.cnblogs.com/mufenglin/p/7479281.html 按照如上方式打包后,执行dist文件夹(新 ...
- Golang 学习资料
资料 1.How to Write Go Code https://golang.org/doc/code.html 2.A Tour of Go https://tour.golang.org/li ...
- python:unittest之跳过测试和预期失败的用例
在利用单元测试框架执行测试用例的过程中,有时只需要执行一部分用例,或者跳过某些暂不需要执行的用例,python的unittest框架就内置这样的功能. 前面的博客介绍了unittest框架的测试用例加 ...
- Sqlserver内存管理:限制最大占用内存(转载)
一.Sqlserver对系统内存的管理原则是:按需分配,且贪婪(用完不还).它不会自动释放内存,因此执行结果集大的sql语句时,数据取出后,会一直占用内存,直到占满机器内存(并不会撑满,还是有个最大限 ...
- SpringMVC处理跨域请求时的一个注意事项
由于公司对SpingMVC框架里面的东西进行了扩展,在配置SpringMVC时没有使用<mvc:annotation-driven>这个标签.而且是自己手动来配置HandlerMa ...
- 分布式系统消息中间件——RabbitMQ的使用思考篇
分布式系统消息中间件--RabbitMQ的使用思考篇 前言 前面的两篇文章分布式系统消息中间件--RabbitMQ的使用基础篇与分布式系统消息中间件--RabbitMQ的使用进阶篇,我们简单介 ...
- elasticsearch开启外网访问
默认情况下,Elastic 只允许本机访问,如果需要远程访问,可以修改 Elastic 安装目录的config/elasticsearch.yml文件,去掉network.host的注释,将它的值改成 ...
- nginx Location 语法基础知识
URL地址匹配是Nginx配置中最灵活的部分 Location 支持正则表达式匹配,也支持条件匹配,用户可以通过location指令实现Nginx对动丶静态网页的过滤处理. Nginx locatio ...
- python第七章:常用模块--小白博客
yagmail模块 python标准库中发送电子邮件的模块比较复杂,因此,有许多开原的库提供了更加易用的接口来发送电子邮件,其中yagmail是一个使用比较广泛的开原项目,yagmail底层依然使用了 ...
- 关于getHibernateTemplate().get()方法
返回的对象值唯一,方法带有两个参数 第一个是意图查询实体的Class 如User.Class ;第二个参数是该实体在数据库中对应的主键值,而且参数的类型要和映射文件相对应. 如 Role role ...