以下是一个案例,有一个店员,负责进货和卖货。进货生产,卖货消费。

当商品超过10件,生产等待,消费继续,当少于0件,消费等待,消费继续。

正常代码如下:

package com.atguigu.juc;/** 生产者和消费者案例*/
public class TestProductorAndConsumer {public static void main(String[] args) {Clerk clerk = new Clerk();Productor pro = new Productor(clerk);Consumer cus = new Consumer(clerk);new Thread(pro, "生产者 A").start();new Thread(cus, "消费者 B").start();}
}
//店员
class Clerk {private int product = 0;//进货public synchronized void get(){//循环次数:0if(product >= 10){System.out.println("产品已满!");try {this.wait();} catch (InterruptedException e) {}}System.out.println(Thread.currentThread().getName() + " : " + ++product);this.notifyAll();}//卖货public synchronized void sale(){//product = 0; 循环次数:0if(product <= 0){System.out.println("缺货!");try {this.wait();} catch (InterruptedException e) {}}System.out.println(Thread.currentThread().getName() + " : " + --product);this.notifyAll();}
}//生产者
class Productor implements Runnable{private Clerk clerk;public Productor(Clerk clerk) {this.clerk = clerk;}@Overridepublic void run() {for (int i = 0; i < 20; i++) {try {Thread.sleep(200);} catch (InterruptedException e) {}clerk.get();}}
}//消费者
class Consumer implements Runnable{private Clerk clerk;public Consumer(Clerk clerk) {this.clerk = clerk;}@Overridepublic void run() {for (int i = 0; i < 20; i++) {clerk.sale();}}
}

运行结果:

很和谐没问题!,生产者每次生产完就等待一下,导致消费者抢到资源,这样导致:0,1轮替。

但是,如果此时再假如一个生产者和消费者:

public class TestProductorAndConsumer {public static void main(String[] args) {Clerk clerk = new Clerk();Productor pro = new Productor(clerk);Consumer cus = new Consumer(clerk);new Thread(pro, "生产者 A").start();new Thread(cus, "消费者 B").start();new Thread(pro, "生产者 C").start();new Thread(cus, "消费者 D").start();}
}

此时运行结果:

可以看到,非常离谱!生产者数量为负数,并且一直没有停止的样子。

分析:

假如最开始是缺货状态,消费者B和D进入都是进入等待的,此时一个生产者抢到资源,进行生产,完事生产了一件,

两个消费者同时唤醒,唤醒了之后,每个消费者都继续下面代码,也就是wait下面的--product,导致数量为负数。

这个时候两个消费者再次进入当然还是等待,一个生产者再次进入,当然效果和上面一样,再次数量在-1的基础上,-1,-2。

这种现象叫做虚假唤醒。

为了解决这个,其实JDK中已经说明了,对于wait方法的使用,必须始终放在while循环中。

每次线程被唤醒之后都得重新进入循环,而不是直接执行下面的--或者++操作。

修改如下:

把上面的if换成while即可:

package com.atguigu.juc;/** 生产者和消费者案例*/
public class TestProductorAndConsumer {public static void main(String[] args) {Clerk clerk = new Clerk();Productor pro = new Productor(clerk);Consumer cus = new Consumer(clerk);new Thread(pro, "生产者 A").start();new Thread(cus, "消费者 B").start();new Thread(pro, "生产者 C").start();new Thread(cus, "消费者 D").start();}
}
//店员
class Clerk {private int product = 0;//进货public synchronized void get(){//循环次数:0while(product >= 10){//为了避免虚假唤醒问题,应该总是使用在循环中System.out.println("产品已满!");try {this.wait();} catch (InterruptedException e) {}}System.out.println(Thread.currentThread().getName() + " : " + ++product);this.notifyAll();}//卖货public synchronized void sale(){//product = 0; 循环次数:0while(product <= 0){System.out.println("缺货!");try {this.wait();} catch (InterruptedException e) {}}System.out.println(Thread.currentThread().getName() + " : " + --product);this.notifyAll();}
}//生产者
class Productor implements Runnable{private Clerk clerk;public Productor(Clerk clerk) {this.clerk = clerk;}@Overridepublic void run() {for (int i = 0; i < 20; i++) {try {Thread.sleep(200);} catch (InterruptedException e) {}clerk.get();}}
}//消费者
class Consumer implements Runnable{private Clerk clerk;public Consumer(Clerk clerk) {this.clerk = clerk;}@Overridepublic void run() {for (int i = 0; i < 20; i++) {clerk.sale();}}
}

生产者与消费者案例-虚假唤醒相关推荐

  1. java多线程生产者与消费者案例_多线程操作实例——生产者与消费者

    面对多线程学习生产者与消费者是最基本的实例 对于java后端开发的人员必须要掌握,还有考研考试计算机操作系统的同鞋. 下面是三个实例对于生产者与消费者的的例子,层层递进,逐步解决问题. 问题:生产者- ...

  2. 【java笔记】线程间通信(2):生产者和消费者案例分析

    [java笔记]线程间通信(1):等待唤醒机制_m0_52043808的博客-CSDN博客 类: 资源类:包子类:皮,馅,有无 生产者: 包子铺类(线程类)(继承Thread) 设置线程任务(run) ...

  3. Java多线程案例--生产者和消费者模型(送奶人和喝奶人的故事!)

    文章目录 一.进程和线程 1.进程 2.线程 3.进程与线程的区别 二.生产者和消费者模型 1.生产者消费者模式概述 2.奶箱类 3.生产者类 4.消费者类 三.测试 1.测试类(BoxDemo) 2 ...

  4. Java实现生产者消费者案例

    目录 一.生产者消费者模式概述 二.生产者消费者案例 三.代码 奶箱类(Box): 生产者类(Producer): 消费者类(Customer): 测试类(BoxDemo): 四.运行结果 一.生产者 ...

  5. 多线程:线程同步与死锁(卖票案例)、线程通信、生产者与消费者

    卖票案例 5个窗口同时卖票: 使用Runnable接口,只创建了一个ticket1对象,5个线程共享此对象,实现了资源共享. public class ticket1 implements Runna ...

  6. 12.多线程的实现方式、线程安全问题的产生与解决以及生产者与消费者问题

    一.实现多线程 1.1 了解多线程 多线程是指从软件或者硬件上实现多个线程并发执行的技术,具有多线程能力的计算机因有硬件支持而能够在同一时间执行多个线程,从而提升性能. 1.2 并发与并行 并行是指同 ...

  7. 笔记-13-多线程 Thread方法 线程安全 生产者和消费者 死锁和阻塞

    1.实现多线程 1.1简单了解多线程[理解] 是指从软件或者硬件上实现多个线程并发执行的技术. 具有多线程能力的计算机因有硬件支持而能够在同一时间执行多个线程,提升性能. 1.2并发和并行[理解] 并 ...

  8. java多线程之生产者和消费者问题

    线程通信:不同的线程执行不同的任务,如果这些任务有某种关系,线程之间必须能够通信,协调完成工作. 经典的生产者和消费者案例(Producer/Consumer): 分析案例: 1):生产者和消费者应该 ...

  9. 作为程序猿必须了解的生产者与消费者

    JUC并发编程三:生产者与消费者(Java) 面试:单例模式,排序算法,生产者与消费者,死锁 代码示例: package PC;/* 线程之间的通信问题:生产者与消费者问题! 等待唤醒,通知唤醒 线程 ...

最新文章

  1. const 是个类型修饰符号。
  2. Moderate Modular Mode %,取模运算性质,数轴,思维
  3. mybatis insert获取主键
  4. javascript 西瓜一期 05-08 计算机的基本组成
  5. linux文件测试操作
  6. 别忘记了修正反欺诈中的这些内容
  7. Kaldi的英文缩写
  8. perl亲身试验ini---使用perl读写配置文件
  9. matlab中ndims函数,matlab中的size(),length(),ndims()函数的用法
  10. android自动化测试抖音,全自动化的抖音启动速度测试
  11. 目标检测工具安装使用--labelImg
  12. c语言学习视频(学c语言看谁的视频)
  13. 全面了解浏览器(内核)发展史
  14. 基于忆阻器的神经网络应用研究
  15. 王道中数据结构的排序算法
  16. 虚拟机VMware下载与安装教程(windows)
  17. 两年后再次遇到的Oracle启动报错,ORA-01012:not logged
  18. ftc文件_美国参议员指责FTC拒绝收集防病毒数据
  19. 苦咖啡·唯一 - 那奇沃夫/KKECHO
  20. 巴别塔合约终端开发日记1-----技术选择

热门文章

  1. 全视曲面屏设计,三星S8又一次走在了行业创新的最前沿
  2. python最佳实践笔记
  3. #ifdef #else #endif 的用法
  4. oracle强制切换redolog组
  5. PHP 入门 - 9.安全
  6. 又收集了一个字体图标站
  7. Gym - 100941G
  8. WPF中引入外部资源
  9. About Gnu Linker2
  10. sql数据库的基本操作