【多线程并发编程】十一 生产者和消费者问题(面试必问)
程序猿学社的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()等待队列中所有的线程
【多线程并发编程】十一 生产者和消费者问题(面试必问)相关推荐
- python 多线程并发编程(生产者、消费者模式),边读图像,边处理图像,处理完后保存图像实现提高处理效率
文章目录 需求 实现 先导入本次需要用到的包 一些辅助函数 如下函数是得到指定后缀的文件 如下的函数一个是读图像,一个是把RGB转成BGR 下面是主要的几个处理函数 在上面几个函数构建对应的处理函数 ...
- 多线程-并发编程(7)-生产者消费者模式及非阻塞队列与阻塞队列实现
生产者消费者模式是一个十分经典的多线程协作模式 弄懂生产者消费者问题能够让我们对多线程编程的理解更加深刻 存在3个元素 1.生产者(类比厨师) 2.生产者的生产产品(类比美食) 3.消费者(类比吃货) ...
- Java 多线程 并发编程
转载自 Java 多线程 并发编程 一.多线程 1.操作系统有两个容易混淆的概念,进程和线程. 进程:一个计算机程序的运行实例,包含了需要执行的指令:有自己的独立地址空间,包含程序内容和数据:不同进 ...
- 【收藏】Java多线程/并发编程大合集
(一).[Java并发编程]并发编程大合集-兰亭风雨 [Java并发编程]实现多线程的两种方法 [Java并发编程]线程的中断 [Java并发编程]正确挂起.恢复.终止线程 [ ...
- Java多线程并发编程
一.线程池 1.1.什么是线程池 线程池是一种多线程的处理方式,利用已有线程对象继续服务新的任务(按照一定的执行策略),而不是频繁地创建销毁线程对象,由此提高服务的吞吐能力,减少CPU的闲置时间.具体 ...
- Java多线程并发编程--Java并发包(JUC)
Java多线程并发–Java并发包(JUC) 前言 前一篇文章中,笔者已经介绍了Java多线程的一些基础知识,但是想要成为一名中高级Java程序员还必须懂得Java并发包(JUC)的知识点,而且JUC ...
- 网易云课堂微专业--Java高级开发工程师--多线程并发编程--学习笔记(二)
文章目录 第一章 多线程并发编程 第二节 线程安全问题 1.2.1 线程安全之可见性问题 多线程中的问题 从内存结构到内存模型 工作内存缓存 指令重排序 内存模型的含义 Shared Variable ...
- 【并发编程十一】c++线程同步——future
[并发编程十一]c++线程同步--future 一.互斥 二.条件变量 三.future 1.promise 1.1.子线程设值,主线程获取 1.2.主线程设置值,子线程获取 2.async 2.1. ...
- 多线程的实际应用-生产者与消费者的例子
多线程的实际应用-生产者与消费者的例子 最近在恶补java多线程的相关知识,正好<java高手真经>课后有一道类似的题目,就拿过来编了一下,在纠结了一阵后,终于写完了,虽然中途瞄了好几眼前 ...
最新文章
- docker配置cdn-容器内可以通过域名访问
- css( div和span)——读书笔记
- 被阻塞的线程唤醒后的逻辑
- java gsoap_gsoap c与java web之间传输字符串中文乱码问题 | 学步园
- centos7环境下ELK部署之elasticsearch
- 通过tomcat日志定位错误
- 自定义的网页加密与解密
- mysql基本功能+show+innodb+索引+慢sql+explain
- 问题 A: 【动态规划】采药_二维数组_一维数组
- 【C#进阶3-4】C#设计模式
- 如何在家优雅地使用 Sci-Hub 免费下载外文文献
- Origin安装Could not connect to Internet Origin installation requires an Internet Connection
- 计算机垃圾清理指令,win7电脑清理垃圾的运行命令代码是什么
- 爱,是一个人成功的最大动力
- 如何免费使用jrebel 和eclipse 项目配合完成热部署功能
- 手机QQ后台清理不掉的秘密——anddroid悬浮窗
- linux编译hashcat,Hashcat用户手册——hashcat在linux系统下的安装
- supermap gis
- 虚拟机 安装 CUDA 可行性分析操作
- 视频去除水印,只需两分钟随时学会
热门文章
- mac电脑听歌下歌那个好?试试lx music desktop!
- Android事件分发-来龙去脉
- java mysql 1366_MySql中的error-code='1366', sqlstate='HY000'错误
- 璀璨之蓝“引爆”全场 讯飞录音笔SR502宝石蓝科技感爆棚
- 阿里生活物联平台笔记一 app配网
- CF 839A - Arya and Bran(水)
- 海康工业相机LabVIEW二次开发——修改参数、存图
- UnityVR--小程序7--坦克对战
- 一起做RGB-D SLAM(4)
- npm编译报错You may need an additional loader to handle the result of these loaders