文档章节

生产者/消费者模式

pan_1308
 pan_1308
发布于 2016/10/27 16:20
字数 995
阅读 311
收藏 0

在实际的软件开发过程中,经常会碰到如下场景:某个模块负责产生数据,这些数据由另一个模块来负责处理(此处的模块是广义的,可以是类、函数、线程、进程等)。产生数据的模块,就形象地称为生产者;而处理数据的模块,就称为消费者。 

单单抽象出生产者和消费者,还够不上是生产者/消费者模式。该模式还需要有一个缓冲区处于生产者和消费者之间,作为一个中介。生产者把数据放入缓冲区,而消费者从缓冲区取出数据。

好处:

1、解耦 

  假设生产者和消费者分别是两个类。如果让生产者直接调用消费者的某个方法,那么生产者对于消费者就会产生依赖(也就是耦合)。将来如果消费者的代码发生变化,可能会影响到生产者。而如果两者都依赖于某个缓冲区,两者之间不直接依赖,耦合也就相应降低了。 

2、支持并发

        使用了生产者/消费者模式之后,生产者和消费者可以是两个独立的并发主体(常见并发类型有进程和线程两种)。生产者把制造出来的数据往缓冲区一丢,就可以再去生产下一个数据。基本上不用依赖消费者的处理速度。其实当初这个模式,主要就是用来处理并发问题的。 

3、支持忙闲不均 
  缓冲区还有另一个好处。如果制造数据的速度时快时慢,缓冲区的好处就体现出来了。当数据制造快的时候,消费者来不及处理,未处理的数据可以暂时存在缓冲区中。等生产者的制造速度慢下来,消费者再慢慢处理掉。 

代码实例:

/**
 * 苹果
 * @author Administrator
 */
public class Apple {

	private int id;
	private String descFlat;
	private String color;
	
	public Apple(int id, String descFlat, String color){
		this.id = id;
		this.descFlat = descFlat;
		this.color = color;
	}
	
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getDescFlat() {
		return descFlat;
	}
	public void setDescFlat(String descFlat) {
		this.descFlat = descFlat;
	}
	public String getColor() {
		return color;
	}
	public void setColor(String color) {
		this.color = color;
	}

	@Override
	public String toString() {
		return "Apple [id=" + id + ", descFlat=" + descFlat + ", color="
				+ color + "]";
	}
}
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

/**
 * 定义篮子  - 多线程模拟实现生产者/消费者模型
 * @author Administrator
 */
public class Basket {

	BlockingQueue<Apple> queue = new LinkedBlockingQueue<Apple>();
	
	// 生产 苹果  // put方法放入一个苹果,若basket满了,等到basket有位置
	public void produce(Apple apple){
		try {
			queue.put(apple); 
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
	
	// 消费 苹果   // take方法取出一个苹果,若basket为空,等到basket有苹果为止(获取并移除此队列的头部)
	public Apple consume(){
		try {
			return queue.take();
		} catch (InterruptedException e) {
			e.printStackTrace();
			return null;
		}
	}
	
}
/**
 * 定义生产者
 * @author Administrator
 */
public class Producer implements Runnable{

	private int instance;
	private Basket basket;	
	private boolean flat;
	
    public Producer(int instance, Basket basket, boolean flat){
    	this.instance = instance;
    	this.basket = basket;
    	this.flat = flat;
    }
	
	public void run() {
		
		System.out.println("开始初始化生产" + instance + "苹果");
		for(int i=0; i<instance; i++){
			Apple apple = new Apple(i,"描述"+i,"红色");
			basket.produce(apple);
		}
		System.out.println("初始化生产了" + instance + "苹果,完毕");
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		
        while(flat){
        	if(basket.queue.size() < instance){
        		System.out.println("库存不足,准备生产了" + instance + "苹果");
        		for(int i=0; i<instance; i++){
        			Apple apple = new Apple(i,"描述"+i,"红色");
        			basket.produce(apple);
        		}
        		System.out.println("已经生产了" + instance + "苹果");
    		}
        	try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
        }
	}
}
/**
 * 消费者
 * @author Administrator
 */
public class Consumer implements Runnable{

    private int instance;
    private Basket basket;
    private boolean flat; 
    
    public Consumer(int instance, Basket basket, boolean flat){
    	this.instance = instance;
    	this.basket = basket;
    	this.flat = flat;
    }
	
	public void run() {
		
		while(flat){
			System.out.println("篮子中苹果数量:" + basket.queue.size());
			if(basket.queue.size() >= instance){
				System.out.println("开始消费....");
				for(int i=0; i<instance; i++){
					Apple apple = basket.consume();
					if(apple != null){
						System.out.println(apple);
					}
				}
				System.out.println("消费....结束");
			}else{
				System.out.println("篮子中 苹果不足...");
				try {
					Thread.sleep(1500);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}
	}

}
public class BlockingQueueTest {

	public static void main(String[] args) {
		// 定义一个 篮子
		Basket basket = new Basket();
		
		int instance = 5;
		boolean flat = true;
		
		// 初始化 生产者
		Producer producer = new Producer(instance, basket,flat);
        new Thread(producer).start();
		
		// 初始化 消费者
		Consumer consumer = new Consumer(instance, basket, flat);
		new Thread(consumer).start();
	}
	
}

 

© 著作权归作者所有

共有 人打赏支持
pan_1308
粉丝 4
博文 95
码字总数 58819
作品 0
黄冈
生产者消费者模式

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

Jeffbond
2017/04/14
0
0
rabbitmq学习记录(六)交换机Exchange-direct

实现功能:一条消息发送给多个消费者 交换机模式:direct 相比于之前的fanout模式,可以进一步的筛选获取消息的消费者。 fanout模式下,只要消费者监听的队列,已经与接收生产者消息的交换机...

人觉非常君
07/20
0
0
并发编程(五)——生产者消费者模式

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

whc20011
2016/10/31
34
0
rabbitmq学习记录(五)交换机Exchange-fanout

之前学习的都是一条消息发给一个消费者,下面开始记录如何把一条信息发给多个消费者 这边我们用到了交换机Exchange 交换机模式:fanout 模式特点:生产者把消息发送给Exchange之后,Exchang...

人觉非常君
07/20
0
0
Java多线程学习(七)

等待/通知模式中最经典的案例当属生产者/消费者模式,此模式有几种变形,但都是基于wait/notify的。 生产者/消费者模式有两种类型:操作值的和操作栈的。下面分别从这两方面来讲解生产者/消费...

kakayang2011
2016/03/07
42
0

没有更多内容

加载失败,请刷新页面

加载更多

Shell特殊符号总结以及cut,sort,wc,uniq,tee,tr,split命令

特殊符号总结一 * 任意个任意字符 ? 任意一个字符 # 注释字符 \ 脱义字符 | 管道符 # #号后的备注被忽略[root@centos01 ~]# ls a.txt # 备注 a.txt[root@centos01 ~]# a=1[root@centos01...

野雪球
今天
2
0
OSChina 周二乱弹 —— 程序员圣衣

Osc乱弹歌单(2018)请戳(这里) 【今日歌曲】 @达尔文:分享Skeeter Davis的单曲《The End of the World》 《The End of the World》- Skeeter Davis 手机党少年们想听歌,请使劲儿戳(这里...

小小编辑
今天
5
0
[ python import module ] 导入模块

import moudle_name ----> import module_name.py ---> import module_name.py文件路径 -----> sys.path (这里进行查找文件) # from app.web import Personimport app.web.Person as Pe......

_______-
昨天
4
0
Redis性能问题排查解决手册

一、性能相关的数据指标 通过Redis-cli命令行界面访问到Redis服务器,然后使用info命令获取所有与Redis服务相关的信息。通过这些信息来分析文章后面提到的一些性能指标。 nfo命令输出的数据可...

IT--小哥
昨天
2
0
mixin混入

①新建mixin.js文件 const mixin = { methods: { /** * 分页公共方法 */ handleSizeChange(val) { this.pageData.size = val; this.query(); }, hand......

不负好时光
昨天
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部