码迷,mamicode.com
首页 > 其他好文 > 详细

生产者消费者模式(吃包子例子)

时间:2015-06-08 23:27:43      阅读:1044      评论:0      收藏:0      [点我收藏+]

标签:多线程   设计模式   线程   编程   

生产者-消费者问题是一个经典的进程同步问 题,该问题最早由Dijkstra提出,用以演示他提出的信号量机制。在同一个进程地址空间内执行的两个线程生产者线程生产物品,然后将物品放置在一个空 缓冲区中供消费者线程消费。消费者线程从缓冲区中获得物品,然后释放缓冲区。当生产者线程生产物品时,如果没有空缓冲区可用,那么生产者线程必须等待消费 者线程释放出一个空缓冲区。当消费者线程消费物品时,如果没有满的缓冲区,那么消费者线程将被阻塞,直到新的物品被生产出来。 

生产者消费者模式是并发、多线程编程中经典的设计模式, 生产者和消费者通过分离的执行工作解耦,简化了开发模式,生产者和消费者可以以不同的速度生产和消费数据。这篇文章我们来看看什么是生产者消费者模式,这 个问题也是多线程面试题中经常被提及的,使用生产者消费者模式的好处。

真实世界中的生产者消费者模式

生产者和消费者模式在生活当中随处可见,它描述的是协调与协作的关系。比如一个人正在准备食物(生产者),而另一个人正在吃(消费者),他们使用一个共用 的桌子用于放置盘子和取走盘子,生产者准备食物,如果桌子上已经满了就等待,消费者(那个吃的)等待如果桌子空了的话。这里桌子就是一个共享的对象。在 Java Executor框架自身实现了生产者消费者模式它们分别负责添加和执行任务。 

它的确是一种实用的设计模式,常用于编写多线程或并发代码。下面是它的一些优点:

1它简化的开发,你可以独立地或并发的编写消费者和生产者,它仅仅只需知道共享对象是谁

2生产者不需要知道谁是消费者或者有多少消费者,对消费者来说也是一样

3生产者和消费者可以以不同的速度执行

4分离的消费者和生产者在功能上能写出更简洁、可读、易维护的代码  


生产者消费者问题是一个流行的面试题,面试官会要求你实现生产者消费者设计模式,以至于能让生产者应等待如果队列或篮子满了的话,消费者等待如果队列或者 篮子是空的。这个问题可以用不同的方式来现实,经典的方法是使用wait和notify方法在生产者和消费者线程中合作,在队列满了或者队列是空的条件下 阻塞,Java5的阻塞队列(BlockingQueue)数据结构更简单,因为它隐含的提供了这些控制,虽然现在你不需要使用wait和nofity在生产 者和消费者之间通信了,阻塞队列的put()方法将阻塞如果队列满了,队列take()方法将阻塞如果队列是空的。在下部分我们看看jdk5之前怎么用java实现生产者和消费者模式。 

下面我就用吃包子者例子


生产者:包子生产者(多个),一次生产一个包子,生产的时间是随机的

缓存区:装包子的篮子(一个),例子里我限定篮子最多能装5个,篮子里面最上面的包子会被先吃掉,所以这用到了数据结构里面的栈,先进后出

消费者:吃包子的消费者(多个),一次只能吃个包子,吃的时间也是随机的


篮子满了生产者就不可以往篮子里放包子,必须得等到篮子不是满的

篮子空了消费者不可以继续吃包子,得等到篮子有包子才能拿包子吃


代码如下

package com.eyugame.test;

import java.util.Arrays;
import java.util.Random;

/**
 * 生产者消费者模式 例子:生产包子者(生产者),吃包子者(消费者),放包子的篮子(栈结构,先进后出,因为篮子里面上面的包子会被先吃掉)
 * 
 * @author JYC506
 * 
 */
/* 放包子的篮子 */
public class StackPack {
	/* 篮子的大小 */
	private int maxSize;
	/* 用来存放包子的数组 */
	private Object[] data;
	/* 最上面包子的位置 */
	private int top;

	/* 构造方法 */
	public StackPack(int maxSize) {
		this.maxSize = maxSize;
		this.data = new Object[maxSize];
		this.top = -1;
	}

	/**
	 * 从篮子拿出一个包子
	 * @param eaterName 包子消费者的名字
	 * @return
	 */
	public synchronized Object eat(String eaterName) {
		/* 如果篮子为空就等到篮子有包子为止 */
		while (this.isEmpty()) {
			System.out.println("篮子空了++++++++++消费者"+eaterName+"得等一下再吃了");
			try {
				this.wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		this.notify();
		Object object = data[top];
		data[top]=null;
		System.out.println(eaterName+"吃了"+object);
		top--;
		return object;
	}

    /**
     * 添加包子
     * @param object 包子
     * @param name 生产者的名称
     * @return
     */
	public synchronized boolean add(Object object,String name) {
		/* 如果篮子满了就等到篮子可以放包子为止 */
		while (this.isFull()) {
			System.out.println("篮子满了-----------生产者"+name+"要等一下再生产");
			try {
				this.wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		this.notify();
		if (object != null) {
			this.top++;
			data[top] = object;
			this.show();
			return true;
		}
		return false;
	}

	/* 判断篮子是否为空 */
	private boolean isEmpty() {
		return this.top == -1;
	}

	/* 判断篮子是否满了 */
	private boolean isFull() {
		return this.top == maxSize - 1;
	}
	
	private void show(){
		System.out.println("篮子里面的包子:"+Arrays.toString(data));
	}

	public static void main(String[] args) {
		/* 创建装包子的篮子 */
		StackPack stackPack = new StackPack(5);
		/* 创建两个生产者,生产的包子放stackPack这个篮子,满了就不能再生产得等 */
		BunHandler bunProducer1 = new BunProducer(stackPack,"A");
		BunHandler bunProducer2 = new BunProducer(stackPack,"B");
		/* 创建3个消费者,吃stackPack篮子里面的包子,篮子如果没有包子得等 */
		BunHandler bunCustomer1 = new BunCustomer(stackPack,"a");
		BunHandler bunCustomer2 = new BunCustomer(stackPack,"b");
		BunHandler bunCustomer3 = new BunCustomer(stackPack,"c");
		/* 生产者开始生产包子 */
		bunProducer1.start();
		bunProducer2.start();
		/* 消费者开始吃包子 */
		bunCustomer1.start();
		bunCustomer2.start();
		bunCustomer3.start();
	}
}

/* 生产者:生产包子的生产者 */
class BunProducer extends BunHandler {

	/* 构造方法 */
	public BunProducer(StackPack stackPack, String name) {
		super(stackPack, name);
	}

	/**
	 * 随机时间生产包子
	 */
	@Override
	void toDo() {
		try {
			while (true) {
				this.stackPack.add("包子" + name,name);
				Thread.sleep(this.random.nextInt(2000) + 1000);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

/* 消费者:吃包子的消费者 */
class BunCustomer extends BunHandler {
	/*构造方法*/
	public BunCustomer(StackPack stackPack, String name) {
		super(stackPack, name);
	}
	/**
	 * 如果篮子没空的话1到3秒随机时间吃一个
	 */
	@Override
	void toDo() {
		try {
			while (true) {
				this.stackPack.eat(this.name);
				Thread.sleep(this.random.nextInt(4000) + 2000);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

/*跟包子有关的抽象对象*/
abstract class BunHandler extends Thread {
	/* 用来产生随机时间 */
	Random random = new Random();
	/* 从指定篮子拿包子 */
	StackPack stackPack;
	/* 名称 */
	String name;
	/**
	 * 
	 * @param stackPack 篮子
	 * @param name  有关对象的名称
	 */
	public BunHandler(StackPack stackPack, String name) {
		this.stackPack = stackPack;
		this.name=name;
	}

	@Override
	public void run() {
		this.toDo();
	}

	abstract void toDo();
}
测试结果

技术分享

生产者消费者模式(吃包子例子)

标签:多线程   设计模式   线程   编程   

原文地址:http://blog.csdn.net/h348592532/article/details/46418169

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!