文档章节

多线程生产者和消费者设计实现

假装是个胖子
 假装是个胖子
发布于 2017/05/14 17:38
字数 2469
阅读 31
收藏 0
点赞 0
评论 0

生产者和消费者是多线程经典案例。这里给出两种实现方案供大家参考。有错的地方欢迎指正。

一:使用synchronized代码块

//产品库,最大数量的20,使用LinkedList作为容器
class Store{

	//产品最大数量
	int MAX_COUNT = 20;
	
	//存放产品的集合
	private List<Product>  list = new LinkedList<Product>();
	
	public List<Product> getList() {
		return list;
	}
	public void setList(List<Product> list) {
		this.list = list;
	}
	
}

//产品类
class Product{
	//产品编号
	private int num;
	//产品名
	private String name;
	
	public Product() {
		super();
		// TODO Auto-generated constructor stub
	}
	public Product(int num, String name) {
		super();
		this.num = num;
		this.name = name;
	}
	@Override
	public String toString() {
		return "Product [num=" + num + ", name=" + name + "]";
	}
	public int getNum() {
		return num;
	}
	public void setNum(int num) {
		this.num = num;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}

}

//生产者
class Producter implements Runnable{
	
	//产品库对象
	private Store store;
	//List(使用产品库中的list对象,监听作用)
	private List<Product>  list;
	
	public Producter(Store store,List<Product>  list) {
		super();
		this.list = list;
		this.store = store;
	}

	@Override
	public void run() {
	
		while(true){
			//list作为监听
			synchronized (list) {
				try {
					Thread.sleep(100);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				if (store.getList().size()<store.MAX_COUNT) {
					Product p = new Product(new Random().nextInt(100),"飞机");
					store.getList().add(p);
					System.out.println(Thread.currentThread().getName()+ p +"被生产");
					list.notifyAll();
				}else{
					System.out.println("====仓库库存已满"+store.getList().size()+"生产暂停====");
					try {
						list.wait();
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					
				}
			}
			
		}
	}
}


//消费者(同生产者)
class Customer implements Runnable{

	private Store store;
	private List<Product>  list;

	public Customer(Store store,List<Product>  list) {
		super();
		this.store = store;
		this.list = list;
	}

	@Override
	public void run() {
		while(true){
			
			synchronized (list) {
				try {
					Thread.sleep(100);
				} catch (InterruptedException e1) {
					e1.printStackTrace();
				}
				if (store.getList().size()>0) {
					System.out.println(Thread.currentThread().getName()+ store.getList().get(0) +"被消费");
					store.getList().remove(0);	
					list.notifyAll();
				}else{
					System.out.println("====仓库库存为"+store.getList().size()+"消费暂停====");
					try {
						list.wait();
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}
		}

	}
}

//测试
public class ThreadDemo {

	public static void main(String[] args) {
		Store store = new Store();
		Producter p = new Producter(store,store.getList());
		Customer c = new Customer(store,store.getList());
		
		Thread p1 = new Thread(p,"生产线程1");
		Thread p2 = new Thread(p,"生产线程2");
		Thread p3 = new Thread(p,"生产线程3");
		Thread c1 = new Thread(c,"消费线程一");
		Thread c2 = new Thread(c,"消费线程二"); 
		
		
		p1.start();
		p2.start();
		p3.start();
		c2.start();
		c1.start();
	}
}

结果:
生产线程1Product [num=90, name=飞机]被生产
生产线程1Product [num=77, name=飞机]被生产
生产线程1Product [num=94, name=飞机]被生产
消费线程二Product [num=90, name=飞机]被消费
消费线程二Product [num=77, name=飞机]被消费
消费线程一Product [num=94, name=飞机]被消费
生产线程3Product [num=83, name=飞机]被生产
生产线程3Product [num=68, name=飞机]被生产
生产线程3Product [num=88, name=飞机]被生产
生产线程2Product [num=66, name=飞机]被生产
生产线程3Product [num=7, name=飞机]被生产
生产线程3Product [num=28, name=飞机]被生产
生产线程3Product [num=83, name=飞机]被生产
消费线程一Product [num=83, name=飞机]被消费
消费线程二Product [num=68, name=飞机]被消费
消费线程二Product [num=88, name=飞机]被消费
消费线程二Product [num=66, name=飞机]被消费
消费线程二Product [num=7, name=飞机]被消费
消费线程二Product [num=28, name=飞机]被消费
生产线程1Product [num=62, name=飞机]被生产
消费线程二Product [num=83, name=飞机]被消费
消费线程二Product [num=62, name=飞机]被消费
====仓库库存为0消费暂停====
====仓库库存为0消费暂停====
生产线程3Product [num=60, name=飞机]被生产
生产线程3Product [num=70, name=飞机]被生产
生产线程3Product [num=64, name=飞机]被生产
生产线程3Product [num=42, name=飞机]被生产
生产线程3Product [num=18, name=飞机]被生产
生产线程2Product [num=42, name=飞机]被生产
生产线程3Product [num=80, name=飞机]被生产
生产线程3Product [num=48, name=飞机]被生产
生产线程3Product [num=91, name=飞机]被生产
生产线程3Product [num=47, name=飞机]被生产
生产线程3Product [num=16, name=飞机]被生产
生产线程3Product [num=27, name=飞机]被生产
生产线程3Product [num=60, name=飞机]被生产
生产线程3Product [num=11, name=飞机]被生产
生产线程3Product [num=51, name=飞机]被生产
生产线程3Product [num=84, name=飞机]被生产
生产线程3Product [num=19, name=飞机]被生产
生产线程3Product [num=54, name=飞机]被生产
生产线程3Product [num=67, name=飞机]被生产
消费线程一Product [num=60, name=飞机]被消费
消费线程二Product [num=70, name=飞机]被消费
消费线程二Product [num=64, name=飞机]被消费
消费线程二Product [num=42, name=飞机]被消费
消费线程二Product [num=18, name=飞机]被消费
消费线程二Product [num=42, name=飞机]被消费
消费线程二Product [num=80, name=飞机]被消费
消费线程二Product [num=48, name=飞机]被消费
消费线程二Product [num=91, name=飞机]被消费
消费线程二Product [num=47, name=飞机]被消费
消费线程二Product [num=16, name=飞机]被消费
消费线程二Product [num=27, name=飞机]被消费
消费线程二Product [num=60, name=飞机]被消费

二:使用LinkedBlockingQueue

//蛋糕类,
class Cake{
	//蛋糕编号
	private int num;
	//蛋糕名,这里我直接都取名叫蛋糕
	private String name;
	public Cake() {
		super();
		// TODO Auto-generated constructor stub
	}
	public Cake(int num, String name) {
		super();
		this.num = num;
		this.name = name;
	}
	public int getNum() {
		return num;
	}
	public void setNum(int num) {
		this.num = num;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	@Override
	public String toString() {
		return "Cake [num=" + num + ", name=" + name + "]";
	}
	
	
}

/**
 * 库存,还是最大20,不过使用了LinkedBlockingQueue作为容器
 * LinkedBlockingQueue会自己维护阻塞,不用我们在wait()和notify(),比较方便,并保证效率
 * @author Asen
 *
 */
class CakeStore{
	//最大库存
	private final int MAX_COUNT = 20;
	
	//cake载体
	 private LinkedBlockingQueue<Cake> list = new LinkedBlockingQueue<Cake>(  
	            20);
	 
	public LinkedBlockingQueue<Cake> getList() {
		return list;
	}

	public void setList(LinkedBlockingQueue<Cake> list) {
		this.list = list;
	}

	public int getMAX_COUNT() {
		return MAX_COUNT;
	}  

}

/**
 * 消费
 * @author Asen
 *
 */
class Consumer implements Runnable{

	private CakeStore cakeStore;
	public Consumer(CakeStore cakeStore) {
		super();
		this.cakeStore = cakeStore;
	}
	@Override
	public void run() {
		while(true){
			if (cakeStore.getList().size()==0) {
				System.out.println("===库存为"+0+"暂停消费===");
			}
			try {
				Cake cake = cakeStore.getList().take();
				System.out.println(Thread.currentThread().getName()+cake+"被消费");
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			
		}
	}
	
}

class Producer implements Runnable{
	
	private CakeStore cakeStore;
	
	
	public Producer(CakeStore cakeStore) {
		super();
		this.cakeStore = cakeStore;
	}

	//生产
	public void run() {
		while(true){
			if (cakeStore.getList().size()==cakeStore.getMAX_COUNT()) {
				System.out.println("===库存满"+cakeStore.getList().size()+"暂停生产===");
			}
			try {
				Cake cake = new Cake(new Random().nextInt(100),"蛋糕");
				cakeStore.getList().put(new Cake(new Random().nextInt(100),"蛋糕"));
				System.out.println(Thread.currentThread().getName()+cake+"被生产");
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
}

//测试
public class TreadBlockingQueue {

	public static void main(String[] args) {
		CakeStore cs = new CakeStore();
		Producer p = new Producer(cs);
		Consumer c = new Consumer(cs);
		
		Thread p1 = new Thread(p,"生产1");
		Thread p2 = new Thread(p,"生产2");
		Thread c1 = new Thread(c,"消费一");
		Thread c2 = new Thread(c,"消费二");
		p1.start();
		c1.start();
		p2.start();
		c2.start();
	}
}


结果:
===库存为0暂停消费===
生产2Cake [num=90, name=蛋糕]被生产
消费二Cake [num=70, name=蛋糕]被消费
===库存为0暂停消费===
生产1Cake [num=66, name=蛋糕]被生产
生产1Cake [num=10, name=蛋糕]被生产
生产1Cake [num=92, name=蛋糕]被生产
生产1Cake [num=7, name=蛋糕]被生产
生产1Cake [num=28, name=蛋糕]被生产
生产1Cake [num=65, name=蛋糕]被生产
生产1Cake [num=69, name=蛋糕]被生产
生产1Cake [num=59, name=蛋糕]被生产
生产1Cake [num=13, name=蛋糕]被生产
生产1Cake [num=68, name=蛋糕]被生产
生产1Cake [num=13, name=蛋糕]被生产
生产1Cake [num=0, name=蛋糕]被生产
生产1Cake [num=18, name=蛋糕]被生产
生产1Cake [num=95, name=蛋糕]被生产
消费二Cake [num=48, name=蛋糕]被消费
消费二Cake [num=2, name=蛋糕]被消费
消费二Cake [num=62, name=蛋糕]被消费
消费二Cake [num=98, name=蛋糕]被消费
消费二Cake [num=59, name=蛋糕]被消费
消费二Cake [num=46, name=蛋糕]被消费
消费二Cake [num=17, name=蛋糕]被消费
消费二Cake [num=94, name=蛋糕]被消费
消费二Cake [num=32, name=蛋糕]被消费
消费二Cake [num=82, name=蛋糕]被消费
消费二Cake [num=81, name=蛋糕]被消费
消费二Cake [num=44, name=蛋糕]被消费
消费二Cake [num=86, name=蛋糕]被消费
消费二Cake [num=46, name=蛋糕]被消费
===库存为0暂停消费===
消费一Cake [num=66, name=蛋糕]被消费
===库存为0暂停消费===
生产2Cake [num=41, name=蛋糕]被生产
生产2Cake [num=59, name=蛋糕]被生产
生产2Cake [num=96, name=蛋糕]被生产
生产2Cake [num=99, name=蛋糕]被生产
生产2Cake [num=4, name=蛋糕]被生产
生产2Cake [num=19, name=蛋糕]被生产
生产2Cake [num=28, name=蛋糕]被生产
生产2Cake [num=47, name=蛋糕]被生产
生产2Cake [num=36, name=蛋糕]被生产
生产2Cake [num=80, name=蛋糕]被生产
生产2Cake [num=52, name=蛋糕]被生产
生产2Cake [num=73, name=蛋糕]被生产
生产2Cake [num=42, name=蛋糕]被生产
生产2Cake [num=40, name=蛋糕]被生产
生产2Cake [num=46, name=蛋糕]被生产
生产2Cake [num=23, name=蛋糕]被生产
消费二Cake [num=87, name=蛋糕]被消费
消费二Cake [num=25, name=蛋糕]被消费
消费二Cake [num=88, name=蛋糕]被消费
消费二Cake [num=69, name=蛋糕]被消费
消费二Cake [num=6, name=蛋糕]被消费
消费二Cake [num=41, name=蛋糕]被消费
消费二Cake [num=10, name=蛋糕]被消费
消费二Cake [num=76, name=蛋糕]被消费
消费二Cake [num=86, name=蛋糕]被消费
消费二Cake [num=64, name=蛋糕]被消费
消费二Cake [num=72, name=蛋糕]被消费
消费二Cake [num=34, name=蛋糕]被消费
消费二Cake [num=98, name=蛋糕]被消费
消费二Cake [num=41, name=蛋糕]被消费
消费二Cake [num=87, name=蛋糕]被消费
===库存为0暂停消费===
生产1Cake [num=36, name=蛋糕]被生产
消费一Cake [num=48, name=蛋糕]被消费
===库存为0暂停消费===
生产2Cake [num=60, name=蛋糕]被生产
消费二Cake [num=11, name=蛋糕]被消费
消费一Cake [num=10, name=蛋糕]被消费
===库存为0暂停消费===
生产1Cake [num=47, name=蛋糕]被生产
===库存为0暂停消费===
消费一Cake [num=40, name=蛋糕]被消费
===库存为0暂停消费===

结语:当然还有其他实现方式,这里就不列举了。

© 著作权归作者所有

共有 人打赏支持
假装是个胖子
粉丝 0
博文 5
码字总数 3577
作品 0
昌平
程序员
生产者/消费者问题的多种Java实现方式

生产者消费者问题是研究多线程程序时绕不开的经典问题之一,它描述是有一块缓冲区作为仓库,生产者可以将产品放入仓库,消费者则可以从仓库中取走产品。解决生产者/消费者问题的方法可分为两...

HenrySun ⋅ 2016/05/04 ⋅ 0

[高并发Java 七] 并发设计模式

什么是设计模式 在软件工程中,设计模式(design pattern)是对软件设计中普遍存在(反复出现)的各种问题 ,所提出的解决方案。这个术语是由埃里希·伽玛(Erich Gamma)等人在1990年代从建...

Hosee ⋅ 2016/02/14 ⋅ 0

谈谈存储软件的无锁设计

面向磁盘设计的存储软件不需要考虑竞争锁带来的性能影响。磁盘存储软件的性能瓶颈点在于磁盘,磁盘抖动会引入极大的性能损耗。因此,传统存储软件的设计不会特别在意处理器的使用效率。曾经对...

wuzhongjie ⋅ 2016/10/04 ⋅ 0

高性能高并发队列-Disruptor

Disruptor是英国外汇交易公司LMAX开发的一个高性能队列,研发的初衷是解决内存队列的延迟问题(在性能测试中发现竟然与I/O操作处于同样的数量级)。基于Disruptor开发的系统单线程能支撑每秒...

满小茂 ⋅ 2016/12/09 ⋅ 0

秒杀多线程第十篇 生产者消费者问题

继经典线程同步问题之后,我们来看看生产者消费者问题及读者写者问题。生产者消费者问题是一个著名的线程同步问题,该问题描述如下:有一个生产者在生产产品,这些产品将提供给若干个消费者去...

长平狐 ⋅ 2012/12/10 ⋅ 0

秒杀多线程第十篇 生产者消费者问题

继经典线程同步问题之后,我们来看看生产者消费者问题及读者写者问题。生产者消费者问题是一个著名的线程同步问题,该问题描述如下:有一个生产者在生产产品,这些产品将提供给若干个消费者去...

晨曦之光 ⋅ 2012/05/21 ⋅ 0

并发编程(五)——生产者消费者模式

在并发编程中使用生产者和消费者模式能够解决绝大多数并发问题。该模式通过平衡生产线程和消费线程的工作能力来提高程序的整体处理数据的速度。 为什么要使用生产者和消费者模式 在线程世界里...

whc20011 ⋅ 2016/10/31 ⋅ 0

Java设计模式 - 生产者、消费者

对于多线程程序来说,不管任何编程语言,生产者和消费者模型都是最经典的。就像学习每一门编程语言一样,Hello World!都是最经典的例子。 实际上,准确说应该是“生产者-消费者-仓储”模型,...

YuanyuanL ⋅ 2015/08/10 ⋅ 0

看看我的这段多线程的代码符不符合题意

我一直对多线程掌握的不够好,感觉没搞透实质,想问下这道题我这样写可不可以,不可以的话,怎么写才更好,真心求教。 这是题目: 采用Java 多线程技术,设计实现一个符合生产者和消费者问题...

倔强 ⋅ 2011/11/03 ⋅ 0

C#多线程学习(三) 生产者和消费者

[1] C#多线程学习(三) 生产者和消费者 [2]C#多线程学习(三) 生产者和消费者 本系列文章导航 C#多线程学习(一) 多线程的相关概念 C#多线程学习(二) 如何操纵一个线程 C#多线程学习(三) 生产者...

Yamazaki ⋅ 2012/03/29 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

熊掌号收录比例对于网站原创数据排名的影响[图]

从去年下半年开始,我在写博客了,因为我觉得业余写写博客也还是很不错的,但是从2017年下半年开始,百度已经推出了原创保护功能和熊掌号平台,为此,我也提交了不少以前的老数据,而这些历史...

原创小博客 ⋅ 17分钟前 ⋅ 0

LVM讲解、磁盘故障小案例

LVM LVM就是动态卷管理,可以将多个硬盘和硬盘分区做成一个逻辑卷,并把这个逻辑卷作为一个整体来统一管理,动态对分区进行扩缩空间大小,安全快捷方便管理。 1.新建分区,更改类型为8e 即L...

蛋黄Yolks ⋅ 35分钟前 ⋅ 0

Hadoop Yarn调度器的选择和使用

一、引言 Yarn在Hadoop的生态系统中担任了资源管理和任务调度的角色。在讨论其构造器之前先简单了解一下Yarn的架构。 上图是Yarn的基本架构,其中ResourceManager是整个架构的核心组件,它负...

p柯西 ⋅ 46分钟前 ⋅ 0

uWSGI + Django @ Ubuntu

创建 Django App Project 创建后, 可以看到路径下有一个wsgi.py的问题 uWSGI运行 直接命令行运行 利用如下命令, 可直接访问 uwsgi --http :8080 --wsgi-file dj/wsgi.py 配置文件 & 运行 [u...

袁祾 ⋅ 今天 ⋅ 0

JVM堆的理解

在JVM中,我们经常提到的就是堆了,堆确实很重要,其实,除了堆之外,还有几个重要的模块,看下图: 大 多数情况下,我们并不需要关心JVM的底层,但是如果了解它的话,对于我们系统调优是非常...

不羁之后 ⋅ 昨天 ⋅ 0

推荐:并发情况下:Java HashMap 形成死循环的原因

在淘宝内网里看到同事发了贴说了一个CPU被100%的线上故障,并且这个事发生了很多次,原因是在Java语言在并发情况下使用HashMap造成Race Condition,从而导致死循环。这个事情我4、5年前也经历...

码代码的小司机 ⋅ 昨天 ⋅ 1

聊聊spring cloud gateway的RetryGatewayFilter

序 本文主要研究一下spring cloud gateway的RetryGatewayFilter GatewayAutoConfiguration spring-cloud-gateway-core-2.0.0.RC2-sources.jar!/org/springframework/cloud/gateway/config/G......

go4it ⋅ 昨天 ⋅ 0

创建新用户和授予MySQL中的权限教程

导读 MySQL是一个开源数据库管理软件,可帮助用户存储,组织和以后检索数据。 它有多种选项来授予特定用户在表和数据库中的细微的权限 - 本教程将简要介绍一些选项。 如何创建新用户 在MySQL...

问题终结者 ⋅ 昨天 ⋅ 0

android -------- 颜色的半透明效果配置

最近有朋友问我 Android 背景颜色的半透明效果配置,我网上看资料,总结了一下, 开发中也是常常遇到的,所以来写篇博客 常用的颜色值格式有: RGB ARGB RRGGBB AARRGGBB 这4种 透明度 透明度...

切切歆语 ⋅ 昨天 ⋅ 0

CentOS开机启动subversion

建立自启动脚本: vim /etc/init.d/subversion 输入如下内容: #!/bin/bash## subversion startup script for the server## chkconfig: 2345 90 10# description: start the subve......

随风而飘 ⋅ 昨天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部