惊!用Java实现生产者消费者问题能这么简单?
Java简单实现生产者消费者问题
单个消费者
今天结束了多线程的学习,使用wait和notify来进行线程间的通信以此实现简易的生产者消费者问题;
首先来看什么是生产者消费者问题:
所谓生产者-消费者问题,实际上主要是包含了两类线程,一种是生产者线程用于生产数据,另一种是消费者线程用于消费数据,为了解耦生产者和消费者的关系,通常会采用共享的数据区域,就像是一个仓库,生产者生产数据之后直接放置在共享数据区中,并不需要关心消费者的行为;而消费者只需要从共享数据区中去获取数据,就不再需要关心生产者的行为。
因此,要解决生产者消费者问题就需要两类线程:一类负责产品生产,一类负责产品消费。然后再设计一个仓库(共享池)存储两个线程访问的共有资源。
因此先构造一个仓库类
class Pool{private int number;//产品个数,大于0即存在产品private final int MAX_NUMBER = 20;//共享池的最大容量public Pool() {//初始化this.number = 0;}public int cost(){//消费行为if (number>0)//当共享池还存在商品时 进行消费return number--;elsereturn 0;}public int getNumber() {//获取当前共享池容量return number;}public boolean addNumber(){//生产行为if (number<MAX_NUMBER) {//共享池中还有空位则进行生产,否则返回falsenumber++;return true;}else {return false;}}
}
再构建一个生产者线程:
Thread adder = new Thread("adder"){//生产者线程@Overridepublic void run() {super.run();for (int i=0;i<100;i++){//让生产者不停的进行生产,直到完成100个生产指标synchronized (pool){//开始生产后对共享池加锁,避免在确认共享池中数量时,共享池数量发生改变,造成不同步。if (!pool.addNumber()){//当共享池满时,生产线程进行休息等待消费者消费并唤醒。因为这次没有进行消 //费所以i标记要-1,保证生产100个商品try {i--;System.out.println("当前共享池中有"+pool.getNumber()+"个商品,共享池已经满了。生产者开始休息");pool.wait();} catch (InterruptedException e) {e.printStackTrace();}}else {//进行生产并唤醒消费者线程System.out.println(getName()+"正在生产,当前共享池中有"+pool.getNumber()+"个商品");pool.notifyAll();};}}System.out.println("生产者已经完成了生产100件商品的任务");}};
生产者线程中的加锁位置需要注意,锁应该加在即将开始对共享池进行修改的位置,如果加在if (!pool.addNumber())下面可能造成开始判断过程中pool中number数据被修改的局面,例如极端情况下刚判断时number满了,但判断完的下一刻,加锁前,消费者完成了一个商品的消费,number-1,这个时候按理生产者应该进行生产,但生产者却进入了等待状态,使得线程不安全。所以 synchronized语句位置需要慎重考虑。
接下来构建消费者线程:
Thread cost1 = new Thread("cost1"){//消费者进程@Overridepublic void run() {super.run();for (int i=0;i<100;i++){//让消费者累计消费100个商品synchronized (pool){//加锁位置同生产者一样,在即将对共享池进行操作时进行加锁。if (pool.getNumber()>0){//对共享池中商品数量进行判断,>0则进行消费,否则进行等待状态,等待消费者线程唤醒。pool.cost();System.out.println(getName()+"消费了第"+(i+1)+"件商品");pool.notify();}else {//i--是因为这次消费者没有进行消费,而是进行了等待。try {i--;System.out.println("共享池中的商品数量:"+pool.getNumber()+",消费者1正在等待生产");pool.wait();} catch (InterruptedException e) {e.printStackTrace();}}}}System.out.println("消费者1完成了消费的任务");}};
之后在main方法中对两个线程启动就可以进行测试
测试结果如下(部分):
....
....
....
cost1消费了第90件商品
cost1消费了第91件商品
cost1消费了第92件商品
cost1消费了第93件商品
cost1消费了第94件商品
cost1消费了第95件商品
cost1消费了第96件商品
cost1消费了第97件商品
共享池中的商品数量:0,消费者1正在等待生产
adder正在生产,当前共享池中有1个商品
adder正在生产,当前共享池中有2个商品
adder正在生产,当前共享池中有3个商品
生产者已经完成了生产100件商品的任务
cost1消费了第98件商品
cost1消费了第99件商品
cost1消费了第100件商品
消费者1完成了消费的任务Process finished with exit code 0
多个消费者
对代码稍微改动,也可以实现一个生产者两个消费者并发的操作:
Thread cost2 = new Thread("cost2"){//消费者2 将循环次数修改为了50次,并将notify方法换成了notifyAll方法,其余代码与消费者一致@Overridepublic void run() {super.run();for (int i=0;i<50;i++){synchronized (pool){if (pool.getNumber()>0){pool.cost();System.out.println(getName()+"消费了第"+(i+1)+"件商品");pool.notifyAll();try {sleep(1);} catch (InterruptedException e) {e.printStackTrace();}}else {try {i--;System.out.println("共享池中的商品数量:"+pool.getNumber()+",消费者2正在等待生产");pool.wait();} catch (InterruptedException e) {e.printStackTrace();}}}}System.out.println("消费者2完成了消费的任务");}};
运行结果(截取了中间部分具有代表性的结果):
.
.
.
adder正在生产,当前共享池中有16个商品
adder正在生产,当前共享池中有17个商品
adder正在生产,当前共享池中有18个商品
adder正在生产,当前共享池中有19个商品
adder正在生产,当前共享池中有20个商品
当前共享池中有20个商品,共享池已经满了。生产者开始休息
cost2消费了第21件商品
cost2消费了第22件商品
cost2消费了第23件商品
cost2消费了第24件商品
cost2消费了第25件商品
cost2消费了第26件商品
cost2消费了第27件商品
cost2消费了第28件商品
cost2消费了第29件商品
cost2消费了第30件商品
cost2消费了第31件商品
cost2消费了第32件商品
cost1消费了第21件商品
cost1消费了第22件商品
cost1消费了第23件商品
cost1消费了第24件商品
cost1消费了第25件商品
cost1消费了第26件商品
cost1消费了第27件商品
cost1消费了第28件商品
共享池中的商品数量:0,消费者1正在等待生产
adder正在生产,当前共享池中有1个商品
adder正在生产,当前共享池中有2个商品
adder正在生产,当前共享池中有3个商品
adder正在生产,当前共享池中有4个商品
.
.
.
.
完整代码
package day21;class Pool{private int number;//产品个数,大于0即存在产品private final int MAX_NUMBER = 20;//共享池的最大容量public Pool() {//初始化this.number = 0;}public int cost(){//消费行为if (number>0)//当共享池还存在商品时 进行消费return number--;elsereturn 0;}public int getNumber() {//获取当前共享池容量return number;}public boolean addNumber(){//生产行为if (number<MAX_NUMBER) {//共享池中还有空位则进行生产,否则返回falsenumber++;return true;}else {return false;}}
}
public class TestThreadPool {public static void main(String[] args) {Pool pool = new Pool();Thread adder = new Thread("adder"){//生产者线程@Overridepublic void run() {super.run();for (int i=0;i<100;i++){//让生产者不停的进行生产,直到完成100个生产指标synchronized (pool){//开始生产后对共享池加锁,避免在确认共享池中数量时,共享池数量发生改变,造成不同步。if (!pool.addNumber()){//当共享池满时,生产线程进行休息等待消费者消费并唤醒。因为这次没有进行消费所以i标记要-1,保证生产100个商品try {i--;System.out.println("当前共享池中有"+pool.getNumber()+"个商品,共享池已经满了。生产者开始休息");pool.wait();} catch (InterruptedException e) {e.printStackTrace();}}else {//进行生产并唤醒消费者线程System.out.println(getName()+"正在生产,当前共享池中有"+pool.getNumber()+"个商品");pool.notifyAll();};}}System.out.println("生产者已经完成了生产100件商品的任务");}};Thread cost1 = new Thread("cost1"){//消费者进程@Overridepublic void run() {super.run();for (int i=0;i<50;i++){//让消费者累计消费100个商品synchronized (pool){//加锁位置同生产者一样,在即将对共享池进行操作时进行加锁。if (pool.getNumber()>0){//对共享池中商品数量进行判断,>0则进行消费,否则进行等待状态,等待消费者线程唤醒。pool.cost();System.out.println(getName()+"消费了第"+(i+1)+"件商品");pool.notifyAll();}else {//i--是因为这次消费者没有进行消费,而是进行了等待。try {i--;System.out.println("共享池中的商品数量:"+pool.getNumber()+",消费者1正在等待生产");pool.wait();} catch (InterruptedException e) {e.printStackTrace();}}}}System.out.println("消费者1完成了消费的任务");}};Thread cost2 = new Thread("cost2"){@Overridepublic void run() {super.run();for (int i=0;i<50;i++){synchronized (pool){if (pool.getNumber()>0){pool.cost();System.out.println(getName()+"消费了第"+(i+1)+"件商品");pool.notifyAll();try {sleep(1);} catch (InterruptedException e) {e.printStackTrace();}}else {try {i--;System.out.println("共享池中的商品数量:"+pool.getNumber()+",消费者2正在等待生产");pool.wait();} catch (InterruptedException e) {e.printStackTrace();}}}}System.out.println("消费者2完成了消费的任务");}};cost1.start();cost2.start();adder.start();}
}
惊!用Java实现生产者消费者问题能这么简单?相关推荐
- Java多线程-生产者消费者问题(多个消费者多个生产者)
Java多线程-生产者消费者问题(多个消费者多个生产者) public class ConsumerProcuderDemo {public static void main(String[] arg ...
- 【Java】生产者消费者模型
[Java]生产者消费者模型 0x1 前言 生产者和消费者问题是线程模型中的经典问题:生产者和消费者在同一时间段内共用同一个存储空间,生产者往存储空间中添加产品,消费者从存储空间中取走产品,当存储空间 ...
- java实现生产者消费者模式
一: 什么是生产者消费者模型 生产者消费者模式是通过一个容器来解决生产者和消费者的强耦合问题.生产者和消费者彼此之间不直接通讯,而通过阻塞队列来进行通讯,所以生产者生产完数据之后不用等待消费者处理,直 ...
- 【Java】生产者消费者模式的三种实现
原文地址:https://blog.csdn.net/u010983881/article/details/78554671 前言 生产者消费者问题是线程模型中的经典问题:生产者和消费者在同一时间段内 ...
- 【Java】生产者消费者模式的实现
前言 生产者消费者问题是线程模型中的经典问题:生产者和消费者在同一时间段内共用同一存储空间,生产者向空间里生产数据,而消费者取走数据. 阻塞队列就相当于一个缓冲区,平衡了生产者和消费者的处理能力.这个 ...
- java实现生产者消费者问题(转)
引言 生产者和消费者问题是线程模型中的经典问题:生产者和消费者在同一时间段内共用同一个存储空间,如下图所示,生产者向空间里存放数据,而消费者取用数据,如果不加以协调可能会出现以下情况: 生产者消费者图 ...
- 基于JAVA的生产者消费者问题
一.需求分析 为了更好地理解进程同步的机制和过程,决定设计实现生产者消费者问题的解决,以实现进程的同步控制. 题目描述:有n个生产者在生产产品,这些产品将提供给m个消费者去消费,为了使生产者和消费者能 ...
- Java多线程生产者消费者调度实现
生产者消费者模型是多线程中最常见的模型,有着广泛的应用.其主要目的是实现一种动态的平衡,让生产者消费者和谐共处,获得最大化的执行效率. 所说的动态平衡其实就是生产者与消费者协作控制仓储,让消费者不至于 ...
- java 生产者消费者_基于JAVA的生产者消费者问题
一.需求分析 为了更好地理解进程同步的机制和过程,决定设计实现生产者消费者问题的解决,以实现进程的同步控制. 题目描述:有n个生产者在生产产品,这些产品将提供给m个消费者去消费,为了使生产者和消费者能 ...
最新文章
- 用margin还是用padding
- 无线节能组的充电问题
- hive查询where join_Hive系列(4):常用函数where,join
- SAP SD-销售模式-寄售(客户寄售)
- 人工智能对医疗和健康产业的冲击和革命——体外克隆
- (四)boost库之正则表达式regex
- WIN8 打开图片内置管理员无法激活此应用
- H3C交换机S5500系列恢复控制台登录口令
- 盲僧一键r闪用什么设置_美加狮R.A.T. PRO X3至尊版带你畅玩模拟飞行
- 云开发的数据库权限机制解读丨云开发101
- ngnix 作用(通俗易懂)【转载】
- kafka 数据可靠性深度解读
- eDiary电子日记本
- 拓端tecdat|R语言中的岭回归、套索回归、主成分回归:线性模型选择和正则化
- 进销存excel_Excel进销存管理套表,自动库存显示应收应付,全函数快捷轻松
- 机器人(RPA路程自动化)RPA流程自动化和AI的区别。
- 杰理AD142A AD145A系列芯片的功能简介
- git切换到旧版本_git如何更新到指定版本,然后再更新到最新版本
- Mobilenet——深度可分离卷积
- PC微信机器人之实战分析微信图片加密解密