wait和notify的虚假唤醒(spurious wakeups)
文章目录
- 1 现象
- 2 虚假唤醒
1 现象
这个词的定义来源于JDK的Object#wait()方法的注解
官方API明确的告诉我们,为了防止发生中断错误以及虚假唤醒的问题,我们需要将wait()方法放在while() 循环中使用
synchronized (obj) {while (<condition does not hold>) {obj.wait();}... // Perform action appropriate to condition
}
实际上在我们去常使用Object的wait()(notify,notifyAll) 方法的时候,也必然伴随着如官方文档那样的标准的写法(while),那么,问题来了,什么是虚假唤醒(spurious wakeups)
2 虚假唤醒
虚假唤醒(spurious wakeups)的现象一般是伴随着当另一个持有了锁的线程去notify(或者是notifyAll())的时候,锁等待(状态:Thread.State = WAITING)在wait()方法上的线程会被唤醒,并重新竞争锁,竞争到锁的线程会继续执行wait()方法之后的代码【注意这里不是重新去执行一遍锁方法】
这里我们举一个例子:(该代码示例来源于网站)
static class Buf {private final int MAX = 5;private final ArrayList<Integer> list = new ArrayList<>();synchronized void put(int v) throws InterruptedException {if (list.size() == MAX) {wait();}list.add(v);notifyAll();}synchronized int get() throws InterruptedException {// line 0 if (list.size() == 0) { // line 1wait(); // line2// line 3}int v = list.remove(0); // line 4notifyAll(); // line 5return v;}synchronized int size() {return list.size();}
}
假设现在有 A,B 两个线程来执行 get 操作,我们假设如下的步骤发生了:
A 拿到了锁 line 0。
A 发现 size==0, (line 1),然后进入等待,并释放锁 (line 2)。
此时 B 拿到了锁,line0,发现 size==0,(line 1),然后进入等待,并释放锁 (line 2)。
这个时候有个线程 C 往里面加了个数据 1,那么 notifyAll 所有的等待的线程都被唤醒了。
AB 重新获取锁,假设又是 A 拿到了。然后他就走到 line 3,移除了一个数据,(line4) 没有问题。
A 移除数据后想通知别人,此时 list 的大小有了变化,于是调用了 notifyAll (line5),这个时候就把 B 给唤醒了,那么 B 接着往下走。
这时候 B 就出问题了,因为其实此时的竞态条件已经不满足了 (size==0)。B 以为还可以删除就尝试去删除,结果就跑了异常了。
上面的这个现象就是虚假唤醒,在if条件下对于条件的判断,都是会触发虚假唤醒,因为持有锁去notify 唤醒在等待wait()的时候,if条件只会去判断一次,如果不通过while判断的化,实际上对于不满足条件下的唤醒操作都是无效操作。
对于这种问题的解决,按照官方文档的指示:都是通过将if条件修改成while
这也解释了为什么wait() 和notify() 方法一般都是在while(条件变量)代码体内
wait和notify的虚假唤醒(spurious wakeups)相关推荐
- 条件变量的虚假唤醒(spurious wakeups)问题
引言 条件变量是我们常用的同步原语之一,它的正确使用方式一般如下图: 在wait端,我们必须把判断布尔条件和wait()放到while循环中,而不能用if语句,原因是可能会引起虚假唤醒. 那么,究竟什 ...
- 多线程并发编程需要注意虚假唤醒Spurious wakeup
虚假唤醒 Spurious wakeup 如果等待线程在没有通知被调用的情况下唤醒,则称为Spurious wakeup. 解决方案就是: 使用while条件判断,更好的方案是避免使用wait这种低 ...
- java中wait和notify的虚假唤醒问题
前言 本篇博客来自 https://www.cnblogs.com/clover-forever/p/12616869.html 自己在此记录一下,方便日后复习. 虚假唤醒的概念 jdk官方文档解释: ...
- [C++11 多线程同步] --- 条件变量的那些坑【条件变量信号丢失和条件变量虚假唤醒(spurious wakeup)】
1 条件变量的信号丢失 1.1 条件变量的信号丢失场景重现 拿生产者和消费者模型举例,看一段示例代码: #include <iostream> #include <vector> ...
- C++条件变量Wait及虚假唤醒
(1) wait(lock): 调用时即阻塞线程,并且调用lock.unlock() (2) wait(lock, conditions): 调用时检查conditions,如果为false,则阻塞线 ...
- java线程打水问题_Java 多线程 wait() 虚假唤醒问题
本文分享 wait() 的虚假唤醒(Spurious Wakeups)问题,会说明什么是虚假唤醒,以及如何解决. 先看一下相关的 java doc: java doc 说由于中断和虚假唤醒可能会发生 ...
- linux虚假唤醒(spurious wakeup)
1.Linux对虚假唤醒的说明 On a multi-processor, it may be impossible for an implementation of pthread_cond_sig ...
- java suprious wakeup_多线程编程中条件变量和的spurious wakeup 虚假唤醒
1. 概述 条件变量(condition variable)是利用共享的变量进行线程之间同步的一种机制.典型的场景包括生产者-消费者模型,线程池实现等. 对条件变量的使用包括两个动作: 1)线程等待某 ...
- java notify唤醒原理_Java wait和notify虚假唤醒原理
自己在此记录一下,方便日后复习. 虚假唤醒的概念 jdk官方文档解释: 所以说在wait和notify一块使用时,如果使用if作为条件时,会有虚假唤醒的情况发生,所以必须使用while作为循环条件.下 ...
最新文章
- js 浅拷贝直接赋值_js 深拷贝 vs 浅拷贝
- XML学习笔记01【xml_基础、xml_约束】
- 网易2019实习生Java编程题
- Spring.NET学习笔记12——面向切面编程(基础篇) Level 300
- 动手学PaddlePaddle(2):房价预测
- atob和btoa的趣谈
- 云计算的概念_云计算概念掀起涨停潮 美利云奠定板块龙头地位
- java学习日记之小技巧(跟着变量走一走)
- 小米9稳定版系统更新:加入水滴屏形状切换开关
- linux查看cpt硬盘命令,Linux基础知识复习之命令篇
- matlab绘制不同线性的直方图,在matlab中绘制多个垂直直方图
- 中国制盐市场销售动态及需求潜力预测报告(新版)2022-2027年
- Hadoop大数据组件简介
- 服务器 'XXXXXX' 上的 MSDTC 不可用。解决方法
- Drupal7 数据库查询
- 【转】经典的劝酒令和挡酒词
- 《高效团队待人技巧》的读书笔记
- 看完这个,css中position的绝对定位相对定位就懂了
- Firefly笔记一之http模块
- 鸿蒙股票今日行情,华为鸿蒙的股票
热门文章
- ViewPage实现Tab 底部导航 (如微信,微票儿主界面)
- 导航上显示某个地点已关闭什么意思_苹果手机中这4个功能最好立马关闭,不然手机耗电特别快...
- 算法:主宰这个世界的10大算法
- Python学习笔记之威虎山武器库
- 深度学习学习率(lr)调参
- 如何关闭android bt配对窗口,Android 连接SSID隐藏网络以及 LEAP 认证的方法
- 爬虫第五章 selenium模块的应用
- python 3.6.6安装fake_Python fake_useragent报错解决方案
- IC验证工程师高效战斗手册--高效验证平台搭建和冒烟测试要注意什么?
- tplogin手机监控虚拟服务器,tplogincn登录首页手机设置