程序猿学社的GitHub,欢迎Star
https://github.com/ITfqyd/cxyxs
本文已记录到github,形成对应专题。

文章目录

  • 前言
  • 1.概念
  • 2.模拟真实业务场景
  • 代码实战
    • 通过synchronized+wait+notifyall实现
    • lock+await+signalAll

前言

生产者和消费者问题,是面试过程中,经常问到的一个问题,本文,就来了解一下,生产者和消费者是怎么一回事。

1.概念

生产者消费者问题是一个著名的线程同步问题,也是我们面试过程中,经常会问到的一个经典面试题,生产者负责生产数据放到缓冲区,消费者负责从缓存中里面取。

  • 注意这个缓冲区的大小是有上限的。
  • 生产者发现供过于求,也就是说生产的速度太快了,也就是说,缓冲区里的数据,远远高于消费者的消费的能力,如果我们不做处理,就会造成速度的堆积,所以,该缓冲区是有上限的。可以理解为一个仓库,只能存放一定数据的产品,仓库都堆放满了,已经无地可放产品了,只能等消费者购买产品后,我们才能继续生产产品。
  • 生产者发现供不应求,说明消费者消费的速度远远高于生产者的速度,这时候,我们就只能耐心的等待。应该避免库里已经没有产品了还在消费。
    提到生产者和消费者,顿时,我们的脑海里面会浮现不少的产品,rabbitmq,kafka,dubbo等等。

2.模拟真实业务场景

深圳某充电桩厂家,有一个小库房,能存放10台充电桩,为了保证不必要的浪费,利益最大化,要求库房满了,就停止生产,也不能造成库存的数据远远小于消费的数量。

代码实战

通过synchronized+wait+notifyall实现

package com.cxyxs.thread.eleven;/*** Description:* 转发请注明来源  程序猿学社 - https://ithub.blog.csdn.net/* Author: 程序猿学社* Date:  2020/2/29 10:25* Modified By:*/
public class Pile {//库存数量private  int sum=0;private int max=10;/*** 生产者*/public synchronized  void pro(){while (sum == max){  //达到最大值说明库存已经满了,无法存放充电桩try {this.wait();    //需要等待消费者,消费后,才能生存} catch (InterruptedException e) {e.printStackTrace();}}sum++;System.out.println(Thread.currentThread().getName()+":剩余充电桩数量为"+sum);this.notifyAll();   //通知消费者,我们库存有充电桩,赶紧来消费}/*** 消费者*/public  synchronized  void consumer(){while (sum == 0){try {this.wait();  //说明库房,充电桩不够了,需要等待充电桩厂家,继续生产充电桩} catch (InterruptedException e) {e.printStackTrace();}}sum --;System.out.println(Thread.currentThread().getName()+":剩余充电桩数量为"+sum);this.notifyAll();  //通知生产厂家,我已经消费了,你可以继续生产充电桩}
}

测试类

package com.cxyxs.thread.eleven;/*** Description:synchronized+wait+notifyall解决生产者和消费者问题* 转发请注明来源  程序猿学社 - https://ithub.blog.csdn.net/* Author: 程序猿学社* Date:  2020/2/29 10:45* Modified By:*/
public class Demo1{public static void main(String[] args) {Pile pile = new Pile();for (int j = 0; j < 3; j++) {new Thread(()->{for (int i = 0; i < 15; i++) {pile.pro();}},"生产者"+j).start();new Thread(()->{for (int i = 0; i < 15; i++) {pile.consumer();}},"消费者"+j).start();}}
}


通过测试结果,我们可以看出,不会存在生产超出库存最大的情况,也不会出现没有产品后还在消费的问题。

  • 重点,注意判断是否进入等待的时候,使用while,而不是if。如果使用if,可能会存在虚假唤醒的问题,所以这里,使用while,再次判断,避免虚假唤醒的问题。

lock+await+signalAll

java1.5版本以后,引入新的三剑客,一代新人换旧人。我们来看一看1.5版本的三剑客都有哪些。

  • lock ----------synchronized
  • wait ---------- await
  • notifyall ----- signal

synchronized可以理解为自动挡,会自动释放锁
Lock可以理解为手动挡,这种方式虽说灵活,但是需要自己手动释放锁,为了防止死锁,我们lock一般与try finally配套使用。

package com.cxyxs.thread.eleven;import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;/*** Description:Lock方式* 转发请注明来源  程序猿学社 - https://ithub.blog.csdn.net/* Author: 程序猿学社* Date:  2020/2/29 18:16* Modified By:*/
public class PileLock {//库存数量private  int sum=0;private int max=10;final Lock lock = new ReentrantLock();private Condition pro= lock.newCondition();private Condition consumer= lock.newCondition();/*** 生产者*/public   void pro(){try {lock.lock();   //上锁while (sum == max){  //达到最大值说明库存已经满了,无法存放充电桩try {pro.await();    //需要等待消费者,消费后,才能生存} catch (InterruptedException e) {e.printStackTrace();}}sum++;System.out.println(Thread.currentThread().getName()+":剩余充电桩数量为"+sum);pro.signalAll();   //通知消费者,我们库存有充电桩,赶紧来消费}finally {lock.unlock();  //重点}}/*** 消费者*/public    void consumer(){try {lock.lock();   //上锁while (sum == 0){try {consumer.await();  //说明库房,充电桩不够了,需要等待充电桩厂家,继续生产充电桩} catch (InterruptedException e) {e.printStackTrace();}}sum --;System.out.println(Thread.currentThread().getName()+":剩余充电桩数量为"+sum);consumer.signalAll();  //通知生产厂家,我已经消费了,你可以继续生产充电桩} finally {lock.unlock();  //重点}}
}

测试类

package com.cxyxs.thread.eleven;/*** Description:synchronized+wait+notifyall解决生产者和消费者问题* 转发请注明来源  程序猿学社 - https://ithub.blog.csdn.net/* Author: 程序猿学社* Date:  2020/2/29 10:45* Modified By:*/
public class Demo1{public static void main(String[] args) {// 通过synchronized+wait+notifyall实现// Pile pile = new Pile();//lock+await+signalPileLock pile = new PileLock();for (int j = 0; j < 3; j++) {new Thread(()->{for (int i = 0; i < 10; i++) {pile.pro();}},"生产者"+j).start();new Thread(()->{for (int i = 0; i < 10; i++) {pile.consumer();}},"消费者"+j).start();}}
}

  • 注意一定要用try finally,通过finally设置解锁,以确保在必要时释放锁定。
  • 我们使用Lock来产生两个Condition对象来管理任务间的通信,一个是生产者,一个是消费者。
  • lock() 获取锁,unlock() 释放锁
  • await() 使当前线程加入 等待队列中,并释放当锁.当其他线程调用signal()会重新请求锁
  • signal会唤醒一个在 await()等待队列中的线程,signalAll会唤醒 await()等待队列中所有的线程

【多线程并发编程】十一 生产者和消费者问题(面试必问)相关推荐

  1. python 多线程并发编程(生产者、消费者模式),边读图像,边处理图像,处理完后保存图像实现提高处理效率

    文章目录 需求 实现 先导入本次需要用到的包 一些辅助函数 如下函数是得到指定后缀的文件 如下的函数一个是读图像,一个是把RGB转成BGR 下面是主要的几个处理函数 在上面几个函数构建对应的处理函数 ...

  2. 多线程-并发编程(7)-生产者消费者模式及非阻塞队列与阻塞队列实现

    生产者消费者模式是一个十分经典的多线程协作模式 弄懂生产者消费者问题能够让我们对多线程编程的理解更加深刻 存在3个元素 1.生产者(类比厨师) 2.生产者的生产产品(类比美食) 3.消费者(类比吃货) ...

  3. Java 多线程 并发编程

    转载自  Java 多线程 并发编程 一.多线程 1.操作系统有两个容易混淆的概念,进程和线程. 进程:一个计算机程序的运行实例,包含了需要执行的指令:有自己的独立地址空间,包含程序内容和数据:不同进 ...

  4. 【收藏】Java多线程/并发编程大合集

    (一).[Java并发编程]并发编程大合集-兰亭风雨    [Java并发编程]实现多线程的两种方法    [Java并发编程]线程的中断    [Java并发编程]正确挂起.恢复.终止线程    [ ...

  5. Java多线程并发编程

    一.线程池 1.1.什么是线程池 线程池是一种多线程的处理方式,利用已有线程对象继续服务新的任务(按照一定的执行策略),而不是频繁地创建销毁线程对象,由此提高服务的吞吐能力,减少CPU的闲置时间.具体 ...

  6. Java多线程并发编程--Java并发包(JUC)

    Java多线程并发–Java并发包(JUC) 前言 前一篇文章中,笔者已经介绍了Java多线程的一些基础知识,但是想要成为一名中高级Java程序员还必须懂得Java并发包(JUC)的知识点,而且JUC ...

  7. 网易云课堂微专业--Java高级开发工程师--多线程并发编程--学习笔记(二)

    文章目录 第一章 多线程并发编程 第二节 线程安全问题 1.2.1 线程安全之可见性问题 多线程中的问题 从内存结构到内存模型 工作内存缓存 指令重排序 内存模型的含义 Shared Variable ...

  8. 【并发编程十一】c++线程同步——future

    [并发编程十一]c++线程同步--future 一.互斥 二.条件变量 三.future 1.promise 1.1.子线程设值,主线程获取 1.2.主线程设置值,子线程获取 2.async 2.1. ...

  9. 多线程的实际应用-生产者与消费者的例子

    多线程的实际应用-生产者与消费者的例子 最近在恶补java多线程的相关知识,正好<java高手真经>课后有一道类似的题目,就拿过来编了一下,在纠结了一阵后,终于写完了,虽然中途瞄了好几眼前 ...

最新文章

  1. docker配置cdn-容器内可以通过域名访问
  2. css( div和span)——读书笔记
  3. 被阻塞的线程唤醒后的逻辑
  4. java gsoap_gsoap c与java web之间传输字符串中文乱码问题 | 学步园
  5. centos7环境下ELK部署之elasticsearch
  6. 通过tomcat日志定位错误
  7. 自定义的网页加密与解密
  8. mysql基本功能+show+innodb+索引+慢sql+explain
  9. 问题 A: 【动态规划】采药_二维数组_一维数组
  10. 【C#进阶3-4】C#设计模式
  11. 如何在家优雅地使用 Sci-Hub 免费下载外文文献
  12. Origin安装Could not connect to Internet Origin installation requires an Internet Connection
  13. 计算机垃圾清理指令,win7电脑清理垃圾的运行命令代码是什么
  14. 爱,是一个人成功的最大动力
  15. 如何免费使用jrebel 和eclipse 项目配合完成热部署功能
  16. 手机QQ后台清理不掉的秘密——anddroid悬浮窗
  17. linux编译hashcat,Hashcat用户手册——hashcat在linux系统下的安装
  18. supermap gis
  19. 虚拟机 安装 CUDA 可行性分析操作
  20. 视频去除水印,只需两分钟随时学会

热门文章

  1. mac电脑听歌下歌那个好?试试lx music desktop!
  2. Android事件分发-来龙去脉
  3. java mysql 1366_MySql中的error-code='1366', sqlstate='HY000'错误
  4. 璀璨之蓝“引爆”全场 讯飞录音笔SR502宝石蓝科技感爆棚
  5. 阿里生活物联平台笔记一 app配网
  6. CF 839A - Arya and Bran(水)
  7. 海康工业相机LabVIEW二次开发——修改参数、存图
  8. UnityVR--小程序7--坦克对战
  9. 一起做RGB-D SLAM(4)
  10. npm编译报错You may need an additional loader to handle the result of these loaders