正解博客:https://blog.csdn.net/u011863767/article/details/59731447

永远在循环(loop)里调用 wait 和 notify,不是在 If 语句

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

有的这样说:(http://www.tuicool.com/articles/a6ram23)

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

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

1
2
3
4
5
6
7
8
// 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
}

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

注意:

1 永远在synchronized的方法或对象里使用wait、notify和notifyAll,不然Java虚拟机会生成 IllegalMonitorStateException。

2 永远在while循环里而不是if语句下使用wait。这样,循环会在线程睡眠前后都检查wait的条件,并在条件实际上并未改变的情况下处理唤醒通知。

3 永远在多线程间共享的对象(在生产者消费者模型里即缓冲区队列)上使用wait。

生产者消费者代码:

https://zhuanlan.zhihu.com/p/20300609 代码有部分问题,修改如下

ProsumerToConsumer类
public class ProsumerToConsumer {

    public static void main(String[] args) throws Exception {

        Person person =new Person();
Thread t1=new Thread(new Producer(person),"生产者t1");
Thread t2=new Thread(new Producer(person),"生产者t2");
Thread t3=new Thread(new Producer(person),"生产者t3");
Thread s1=new Thread(new Consumer(person), "消费者s1");
Thread s2=new Thread(new Consumer(person), "消费者s2");
Thread s3=new Thread(new Consumer(person), "消费者s3"); s1.start();
s2.start();
Thread.sleep(2000);
t1.start();
t2.start();
t3.start(); } }

  producer代码:

public class Producer implements Runnable {

    private Person person;
// private String name; public Producer( Person person) {
this.person=person;
// this.name=name;
} @Override
public void run() {
try {
person.producer();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}

  consumer代码:

public class Consumer implements Runnable{

    private Person person;

     public Consumer( Person person) {
this.person=person;
} @Override
public void run() { try {
person.consumer();
} catch (Exception e) {
e.printStackTrace();
}
}
}

  person代码:

public class Person {

    private static volatile int num=0;
private Object obj= new Object(); private static final int MAX_NUM=5; public void producer()throws InterruptedException{ while(true){
synchronized (obj) {
while(num==MAX_NUM) {
System.out.println("box is full,size = " + num);
obj.wait();
}
num++;
System.out.println( Thread.currentThread().getName()+ num);
obj.notifyAll();
}
}
} public void consumer() throws InterruptedException{
while (true) {
synchronized (obj) {
while (num==0) {
System.out.println("box is empty,size = " + num);
obj.wait();
}
num--;
obj.notifyAll();
System.out.println(Thread.currentThread().getName() + num);
}
}
}
}

实例验证1:如果判断用的是while  数据在队列容量范围之内。

while(num==MAX_NUM)
        while(true){
synchronized (obj) {
while(num==MAX_NUM) {
System.out.println("box is full,size = " + num);
obj.wait();
}

实例验证2:如果判断用的是if  ,数据已经超出了队列的容量

if(num==MAX_NUM) 
        while(true){
synchronized (obj) {
if(num==MAX_NUM) {
System.out.println("box is full,size = " + num);
obj.wait();
}

多线程-生产者消费者(synchronized同步)的更多相关文章

  1. java+反射+多线程+生产者消费者模式+读取xml(SAX)入数据库mysql-【费元星Q9715234】

    java+反射+多线程+生产者消费者模式+读取xml(SAX)入数据库mysql-[费元星Q9715234] 说明如下,不懂的问题直接我[费元星Q9715234] 1.反射的意义在于不将xml tag ...

  2. 使用Win32 API实现生产者消费者线程同步

    使用win32 API创建线程,创建信号量用于线程的同步 创建信号量 语法例如以下 HANDLE semophore; semophore = CreateSemaphore(lpSemaphoreA ...

  3. Java实现多线程生产者消费者模式的两种方法

    生产者消费者模式:生产者和消费者在同一时间段内共用同一存储空间,生产者向空间里生产数据,而消费者取走数据.生产者生产一个,消费者消费一个,不断循环. 第一种实现方法,用BlockingQueue阻塞队 ...

  4. java实现多线程生产者消费者模式

    1.概念 生产者消费者模式就是通过一个容器来解决生产者和消费者的强耦合问题.生产者和消费者彼此之间不直接通讯,而通过阻塞队列来进行通讯,所以生产者生产完数据之后不用等待消费者处理,直接扔给阻塞队列,消 ...

  5. java多线程 生产者消费者模式

    package de.bvb; /** * 生产者消费者模式 * 通过 wait() 和 notify() 通信方法实现 * */ public class Test1 { public static ...

  6. Java实现多线程生产者消费者模型及优化方案

    生产者-消费者模型是进程间通信的重要内容之一.其原理十分简单,但自己用语言实现往往会出现很多的问题,下面我们用一系列代码来展现在编码中容易出现的问题以及最优解决方案. /* 单生产者.单消费者生产烤鸭 ...

  7. Python多线程-生产者消费者模型

    用多线程和队列来实现生产者消费者模型 # -*- coding:utf-8 -*- __author__ = "MuT6 Sch01aR" import threading imp ...

  8. [多线程] 生产者消费者模型的BOOST实现

    说明 如果 使用过程中有BUG 一定要告诉我:在下面留言或者给我邮件(sawpara at 126 dot com) 使用boost::thread库来实现生产者消费者模型中的缓冲区! 仓库内最多可以 ...

  9. 操作系统实验 windows编程多线程 生产者消费者问题 画圆画方(内置bug版)

    实验3:随便写的 #include <windows.h> #include <string> #include <stdio.h> #pragma warning ...

随机推荐

  1. python爬虫播放mp3

    我不明白这里出了什么问题.每次我试图在pyglet播放声音,我得到以下错误:WAVEFormatException: AVbin is required to decode compressed me ...

  2. Spark分区实例(teacher)

    package URL1 import org.apache.spark.Partitioner import scala.collection.mutable class MyPartitioner ...

  3. python二级考试知识点——turtle、random、time、PyInstaller、jieba、wordcloud

    turtle库(必考) 1.from turtle import * #导入turtle库中的所有方法 2.turtle.pensize(size) #画笔的大小 3.turtle.pencolor( ...

  4. 描述下fastJSON,jackson等等的技术

    ①Jackson:依赖的jar包较少,简单易用性能高,更新速度也比较快,但是对于复杂类型的json转换bean会出 现问题,一些集合Map,List的转换出现问题,对于复杂类型的bean转换Json, ...

  5. C++ 11的移动语义

    目录 可拷贝和可移动的概念 移动构造函数和移动赋值函数 小结移动构造和移动赋值 std::move() 使用 std::move 实现一个高效的 swap 函数 Move and swap 技巧 参考 ...

  6. 论文阅读 | Combating Adversarial Misspellings with Robust Word Recognition

    对抗防御可以从语义消歧这个角度来做,不同的模型,后备模型什么的,我觉得是有道理的,和解决未登录词的方式是类似的,毕竟文本方面的对抗常常是修改为UNK来发生错误的.怎么使用backgroud model ...

  7. python的学习之路(四)

    #迭代器,取值只能用next方法,不能随意取值name = iter([11,22,33,44])print(name.__next__())print(name.__next__())print(n ...

  8. JAVA基础--JAVA API常见对象(字符串&缓冲区)

    一. String 类型 1. String类引入 第二天学习过Java中的常量:   常量的分类:   数值型常量:整数,小数(浮点数) 字符型常量:使用单引号引用的数据 字符串常量:使用双引号引用 ...

  9. 2019中山纪念中学夏令营-Day1[JZOJ]

    T1 题目描述: 1999. Wexley接苹果(apple) (File IO): input:apple.in output:apple.out 时间限制: 1000 ms  空间限制: 1280 ...

  10. EXKMP模版

    这道题目折腾了我好一会啊,出于尊重我要先放我们师兄的博客 1178: [视频]EXKMP模版:最长共同前缀长度 时间限制: 1 Sec  内存限制: 128 MB提交: 180  解决: 123[提交 ...