文档章节

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

假装是个胖子
 假装是个胖子
发布于 2017/05/14 17:38
字数 2469
阅读 37
收藏 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
89
0
[高并发Java 七] 并发设计模式

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

Hosee
2016/02/14
6.7K
0
Java多线程生产者消费者实例

Java生产者消费者实例 设计:涉及到的类有食物、厨师、服务员、顾客以及测试类。厨师负责生产食物,服务员服务于顾客,顾客负责点餐以及吃饭。 技术点:Java多线程,线程安全(synchronized),...

cicadaT
2017/11/05
0
1
高性能高并发队列-Disruptor

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

满小茂
2016/12/09
747
0
秒杀多线程第十篇 生产者消费者问题

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

长平狐
2012/12/10
54
0

没有更多内容

加载失败,请刷新页面

加载更多

play framework 如何支持多数据源

有段时间没有写博客了,但今天又写一篇了,主要是因为这事有一丝自己的思考和动手实践,所以就记录下来了。 现有的问题: play 1.2.4 两台数据库服务器,但是play1.2.4 并不支持同时连接两台...

tuerqidi
15分钟前
0
0
Mysql only_full_group_by解析

查看当前数据库模式: select @@sql_mode; 原因: mysql 5.7中的sql_mode的值中包含'ONLY_FULL_GROUP_BY'; 处理:执行以下SQL set GLOBAL sql_mode ='STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,N......

bug_404
16分钟前
0
0
防止表单重复提交

1:前端方式(治标不治本) $("#admin-role-save").click(function(){//admin-role-save为submit的idvar ts=$(this);var ts_old_val=ts.val();ts.val("提交中....");ts.att...

uug
16分钟前
0
0
保持屏幕常亮

getWindow().setFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON, WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); 在act的created方法中调用即可,一般是播放视频的时候......

Carbenson
17分钟前
0
0
智能合约实施指南

与区块链技术一样,智能合约在商业领域也非常有价值。 为了让我们的读者彻底了解智能合约是什么以及它们如何影响现代商业的交易方式,我们准备了本指南。 集中商业模式正在给去中心化的模式让...

geek12345
19分钟前
0
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部