notify丢失、虚假唤醒
notify丢失:
假设线程A因为某种条件在条件队列中等待,同时线程B因为另外一种条件在同一个条件队列中等待,也就是说线程A/B都被同一个Object.wait()挂起,但是等待的条件不同。
现在假设线程B的线程被满足,线程C执行一个notify操作,此时JVM从Object.wait()的多个线程(A/B)中随机挑选一个唤醒,不幸的是唤醒了A。此时A的条件不满足,于是A继续挂起。而此时B仍然在傻傻的等待被唤醒的信号。也就是说本来给B的通知却被一个无关的线程持有了,真正需要通知的线程B却没有得到通知,而B仍然在等待一个已经发生过的通知。
如果使用notifyall,则能够避免此问题。notifyall会唤醒所有正在等待的线程,线程C发出的通知线程A同样能够收到,但是由于对于A没用,所以A继续挂起,而线程B也收到了此通知,于是线程B正常被唤醒。
既然notifyall能够解决单一notify丢失通知的问题,那么为什么不总是使用notifyall替换notify呢?
假设有N个线程在条件队列中等待,调用notifyall会唤醒所有线程,然后这N个线程竞争同一个锁,最多只有一个线程能够得到锁,于是其它线程又回到挂起状态。这意味每一次唤醒操作可能带来大量的上下文切换(如果N比较大的话),同时有大量的竞争锁的请求。这对于频繁的唤醒操作而言性能上可能是一种灾难。
如果说总是只有一个线程被唤醒后能够拿到锁,那么为什么不使用notify呢?所以某些情况下使用notify的性能是要高于notifyall的。
如果满足下面的条件,可以使用单一的notify取代notifyall操作:
相同的等待者,也就是说等待条件变量的线程操作相同,每一个从wait放回后执行相同的逻辑,同时一个条件变量的通知至多只能唤醒一个线程。
lock上可以存在多个等待队列,应该可以比较好的解决notify丢失的问题。
wait最好放在while循环中,以避免“虚假唤醒”的情形。即线程由于某些特殊情况,不是被notify或者notifyAll所唤醒,所以还需要再次判断条件是否成立。
所以wait应该放到while循环中,而不是简单的使用if条件来判断。
notify丢失、虚假唤醒的更多相关文章
- Java-JUC(八):使用wait,notify|notifyAll完成生产者消费者通信,虚假唤醒(Spurious Wakeups)问题出现场景,及问题解决方案。
模拟通过线程实现消费者和订阅者模式: 首先,定义一个店员:店员包含进货.卖货方法:其次,定义一个生产者,生产者负责给店员生产产品:再者,定义一个消费者,消费者负责从店员那里消费产品. 店员: /** ...
- 刨根问底系列(1)——虚假唤醒(spurious wakeups)的原因以及在pthread_cond_wait、pthread_cond_singal中使用while的必要性
刨根问底之虚假唤醒 1. 概要 将会以下方式展开介绍: 什么是虚假唤醒 什么原因会导致虚假唤醒(两种原因) 为什么系统内核不从根本上解决虚假唤醒这个"bug"(两个原因) 开发者如 ...
- JUC虚假唤醒(六)
为什么条件锁会产生虚假唤醒现象(spurious wakeup)? 在不同的语言,甚至不同的操作系统上,条件锁都会产生虚假唤醒现象.所有语言的条件锁库都推荐用户把wait()放进循环里: whil ...
- (三)juc高级特性——虚假唤醒 / Condition / 按序交替 / ReadWriteLock / 线程八锁
8. 生产者消费者案例-虚假唤醒 参考下面生产者消费者案例: /* * 生产者和消费者案例 */ public class TestProductorAndConsumer { public stat ...
- java多线程 生产者消费者案例-虚假唤醒
package com.java.juc; public class TestProductAndConsumer { public static void main(String[] args) { ...
- 【转】pthread_cond_signal 虚假唤醒问题
引用:http://blog.csdn.net/leeds1993/article/details/52738845 什么是虚假唤醒? 举个例子,我们现在有一个生产者-消费者队列和三个线程. I.1号 ...
- pthread_cond_wait虚假唤醒
pthread_cond_wait中的while()不仅仅在等待条件变量前检查条件cond_is_false是否成立,实际上在等待条件变量后也检查条件cond_is_false是否成立.在多线程等待的 ...
- 多线程编程中条件变量和的spurious wakeup 虚假唤醒
1. 概述 条件变量(condition variable)是利用共享的变量进行线程之间同步的一种机制.典型的场景包括生产者-消费者模型,线程池实现等. 对条件变量的使用包括两个动作: 1) 线程等待 ...
- 什么是虚假唤醒 spurious wakeup
解释一下什么是虚假唤醒? 说具体的例子,比较容易说通. pthread_mutex_t lock; pthread_cond_t notempty; pthread_cond_t notfull; v ...
随机推荐
- Qt 共享库(动态链接库)和静态链接库的创建及调用
前言: 编译器 Qt Creator, 系统环境 win7 64 位 1.创建共享库: 新建文件或项目->选择 Library 和 c++ 库->选择共享库->下一步(工程名为 sh ...
- java web开发 高并发处理
转自:http://blog.csdn.net/zhangzeyuaaa/article/details/44542161 java处理高并发高负载类网站中数据库的设计方法(java教程,java处理 ...
- Dockerfile中CMD和ENTRYPOINT的区别
当启动一个容器时,CMD和ENTRYPOINT都可以用来执行启动命令.但它们的具体用法还是有一些区别: 1. Dockerfile必须至少指定CMD或者ENTRYPOINT其中的一个. 2. ENTR ...
- js定时器之setTimeout的使用
之前用过定时器,只不过用的不是很多,关于js定时器,一般而言我们很容易想到setInterval和setTimeout这两种. 刚开始学js定时器时,记住了setInterval,该方法一般用于每隔多 ...
- JavaScript八张思维导图—编程风格
JS基本概念 JS操作符 JS基本语句 JS数组用法 Date用法 JS字符串用法 JS编程风格 JS编程实践 不知不觉做前端已经五年多了,无论是从最初的jQuery还是现在火热的Angular,Vu ...
- php switch case语句用法
- 虚拟主机、VPS以及云主机的区别和对比
对于很多需要建网站的朋友来说,虚拟主机是必须要了解的基础知识.虚拟主机相对于VPS与云主机来说出现的较早,也是被大多数站长所了解的主机.很多人容易将这三者混淆,弄不清楚三者的联系与区别.那么虚拟主机. ...
- -------- ROOTKIT 核心技术——系统服务调度表挂钩调试(PART III) --------
---------------------------------------------------------------------------------------- 本篇开始进行真枪实弹的 ...
- 红米 Note3 (kenzo)刷入 Lineage OS
红米 Note3 (kenzo)刷入Lineage OS 的过程 详细的教程请看 Install LineageOS on kenzo 本文做一些额外的补充 0 刷机之的准备工作 如果登陆了 Goog ...
- 配置SESSION超时与请求超时
<!--项目的web.xml中 配置SESSION超时,单位是min.用户在线时间.如果不设置,tomcat下的web.xml的session-timeout为默认.--><sess ...