永远在循环(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. 中国剩余定理 (POJ 1006)

    http://poj.org/problem?id=1006      在<孙子算经>中有这样一个问题:“今有物不知其数,三三数之剩二(除以3余2),五五数之剩三(除以5余3),七七数之剩 ...

  2. SSM_CRUD新手练习(4)修改生成的mapper.xml映射文件

    我们为什么要修改呢,这是因为我们查询的时候,我们有时候需要连表查询,例如我们需要查询出员工表的信息(emp_id,emp_name...)与此同时,我们还想查询出该员工所在的部门(dept_name) ...

  3. 第86讲:Scala中For表达式的生成器、定义和过滤器

    今天我们来看一下For表达式中的生成器,定义和过滤等内容. 让我们来看下代码 def main(args:Array[String]){     val lauren = Persons(" ...

  4. 第82讲:Scala中List的ListBuffer是如何实现高效的遍历计算的?

    今天学习下list中的ListBuffer实现的高效计算.让我们先来看下代码 def main(args:Array[String]){        val list = List(1,2,3,4, ...

  5. Python自动化开发 - 网络编程

    本节内容 1.客户端/服务器架构 2.OSI七层 3.socket层 4.socket是什么 5.套接字发展史及分类 6.套接字工作流程 一.客户端/服务器架构 即Client/Server架构,包括 ...

  6. Memcached和Memcache安装(64位win2008)

    一.Memcached和Memcache的区别: 网上关于Memcached和Memcache的区别的理解众说纷纭,我个人的理解是: Memcached是一个内存缓存系统,而Memcache是php的 ...

  7. 我的ecshop二次开发经验分享

    https://jingyan.baidu.com/article/358570f65dbad2ce4724fcc7.html

  8. [Proposal]Nano-Diary(纳日记)

    [Motivation] 很多人都有记日记的习惯,不为别的,就为了那份情怀.但是也有很多人不记日记,原因是嫌写字麻烦.记得很久很久以前,在<读者>上读过一篇文章,大意是一个人用数值记下每天 ...

  9. MySQL5.7Gtid主从复制总是遇到日志被清等出现无法正常主从复制

    最近最是在MySQL5.7上的的gtid主从复制问题总是遇上下面问题: Last_Error: Coordinator stopped because there were error(s) in t ...

  10. SignalR简介

    什么是SignalR? ASP.NET SignalR是ASP.NET开发人员的库,它简化了向应用程序添加实时Web功能的过程.实时Web功能是指服务器代码在连接的客户端可用时立即将内容推送到连接的客 ...