永远在循环(loop)里调用 wait 和 notify,不是在 If 语句现在你知道wait应该永远在被synchronized的背景下和那个被多线程共享的对象上调用,下一个一定要记住的问题就是,你应该永远在while循环,而不是if语句中调用wait。因为线程是在某些条件下等待的——在我们的例子里,即“如果缓冲区队列是满的话,那么生产者线程应该等待”,你可能直觉就会写一个if语句。但if语句存在一些微妙的小问题,导致即使条件没被满足,你的线程你也有可能被错误地唤醒。所以如果你不在线程被唤醒后再次使用while循环检查唤醒条件是否被满足,你的程序就有可能会出错——例如在缓冲区为满的时候生产者继续生产数据,或者缓冲区为空的时候消费者开始消耗数据。所以记住,永远在while循环而不是if语句中使用wait!

因为在多核处理器环境中,Signal唤醒操作可能会激活多于一个线程(阻塞在条件变量上的线程),使得多个调用等待的线程返回。所以用while循环对condition多次判断,可以避免这种假唤醒。

基于以上认知,下面这个是使用wait和notify函数的规范代码模板:

// The standard idiom for calling the wait method in Java
synchronized(sharedObject) {
while(condition) {
sharedObject.wait();
// (Releases lock, and reacquires on wakeup)
}
// do action based upon condition e.g. take or put into queue
}

Ps:在while循环里使用wait的目的,是在线程被唤醒的前后都持续检查条件是否被满足。如果条件并未改变,wait被调用之前notify的唤醒通知就来了,那么这个线程并不能保证被唤醒,有可能会导致死锁问题。

注意:

  1. 永远在synchronized的方法或对象里使用wait、notify和notifyAll,不然Java虚拟机会生成 IllegalMonitorStateException。
  2. 永远在while循环里而不是if语句下使用wait。这样,循环会在线程睡眠前后都检查wait的条件,并在条件实际上并未改变的情况下处理唤醒通知。
  3. 永远在多线程间共享的对象(在生产者消费者模型里即缓冲区队列)上使用wait。

生产者消费者模式中条件判断是使用while而不是if的更多相关文章

  1. Java笔记1 : 在生产者消费者模式中,线程通信与共享数据,死锁问题与解决办法

    本例定义了4个类,这里说一下,方便下面讲解.分别是Product(产品),Producer(生产者),Consumer(消费者), Test(测试类). 多线程之间通信与共享数据只要引用同一内存区域就 ...

  2. java ReentrantLock结合条件队列 实现生产者-消费者模式 以及ReentratLock和Synchronized对比

    package reentrantlock; import java.util.ArrayList; public class ProviderAndConsumerTest { static Pro ...

  3. 使用BlockingQueue的生产者消费者模式

    BlockingQueue很好的解决了多线程中,如何高效安全“传输”数据的问题.通过这些高效并且线程安全的队列类,为我们快速搭建高质量的多线程程序带来极大的便利.使用场景. 首先它是一个队列,而一个队 ...

  4. Java并发程序设计(十一)设计模式与并发之生产者-消费者模式

    设计模式与并发之生产者-消费者模式 生产者-消费者模式是一个经典的多线程设计模式.它为多线程间的协作提供了良好的解决方案.在生产者-消费者模式中,通常由两类线程,即若干个生产者线程和若干个消费者线程. ...

  5. 关于java中生产者消费者模式的理解

    在说生产者消费者模式之前,我觉得有必要理解一下 Obj.wait(),与Obj.notify()方法.wait()方法是指在持有对象锁的线程调用此方法时,会释放对象锁,同时休眠本线程.notify() ...

  6. 10 阻塞队列 & 生产者-消费者模式

    原文:http://www.cnblogs.com/dolphin0520/p/3932906.html 在前面我们接触的队列都是非阻塞队列,比如PriorityQueue.LinkedList(Li ...

  7. 转:Task任务调度实现生产者消费者模式

    我们经常会遇到生产者消费者模式,比如前端各种UI操作事件触发后台逻辑等.在这种典型的应用场景中,我们可能会有4个业务处理逻辑(下文以P代表生产者,C代表消费者): 1. FIFO(先进先出)      ...

  8. Java设计模式—生产者消费者模式(阻塞队列实现)

    生产者消费者模式是并发.多线程编程中经典的设计模式,生产者和消费者通过分离的执行工作解耦,简化了开发模式,生产者和消费者可以以不同的速度生产和消费数据.这篇文章我们来看看什么是生产者消费者模式,这个问 ...

  9. Java 生产者消费者模式详细分析

    */ .hljs { display: block; overflow-x: auto; padding: 0.5em; color: #333; background: #f8f8f8; } .hl ...

随机推荐

  1. js监听键盘触发按钮事件,回车提交表单

    /*回车提交表单*/ $(document).keydown(function(event){ if(event.keyCode == 13){ //alert('你按下了Enter'); $(&qu ...

  2. python.csv 按行按列读取

    参考:https://blog.csdn.net/ly_ysys629/article/details/55107237 # header=0,表示文件第0行为列索引 # index_col=0,表示 ...

  3. python_day1_python第一个程序 hello world

    Python 第一个程序 1)安装好python后,cmd进入DOS下,直接输入python Python 3.6.0 (v3.6.0:41df79263a11, Dec 23 2016, 08:06 ...

  4. *单链表[递归&不带头结点]

    不带头结点的单链表,递归法比较简明!(必背!) 单链表的结构: typedef struct node{ int data; struct node *next; }*List,Node; 创建第一种 ...

  5. day26(分页查询)

    分页查询思路 问题: 服务器向浏览器想用数据很多的时候可以对数据进行封装. domain层  封装数据 package com.baidu.domain; import java.util.List; ...

  6. web-day16

    第16章WEB16-Listener&Filter篇 今日任务 使用过滤器完成自动登录的案例 使用过滤器统一网站的字符集编码 教学导航 教学目标 了解常见的监听器 理解过滤器的生命周期 能够使 ...

  7. web-day10

    第10章WEB10-requet&response篇 今日任务 登录系统后完成文件下载 商城系统注册功能. 教学导航 教学目标 掌握response设置响应头 掌握response重定向和转发 ...

  8. Nginx 实现端口转发

    https://www.cnblogs.com/zhaoyingjie/p/7248678.html Nginx 实现端口转发 什么是端口转发 当我们在服务器上搭建一个图书以及一个电影的应用,其中图书 ...

  9. 关于等效的物理意义 On the Physical Meaning of Equivalence

    当我们谈到两个物理概念是等效的,这意味着: 1.它们拥有同样的属性.例如质量和能量都可以弯曲空间. 2.它们可以在设计实验中无法区分彼此.例如恒星系统中行星的质量与恒星的引力. 3.它们可以互相转化. ...

  10. asp.net core sdk & runtime 镜像[已更新至2.2.0]

    在官方镜像的脚本上, 增加了System.Drawing相关的依赖库 以北京时间为默认的时间 2.2.0 Windows SDK地址: 官方: https://dotnetcli.blob.core. ...