本文主要是介绍JAVA设计模式之生产者-消费模式,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
一、简介
生产者消费者模式并不是GOF提出的23种设计模式之一,23种设计模式都是建立在面向对象的基础之上的,但其实面向过程的编程中也有很多高效的编程模式,生产者消费者模式便是其中之一,它是我们编程过程中最常用的一种设计模式。
拿生活中的例子来说,工厂生产出来的产品总是要输出到外面使用的,这就是生产与消费的概念。
在软件开发过程中,经常会碰到如下场景:某个模块负责产生数据,这些数据由另一个模块来负责处理(此处的模块是广义的,可以是类、函数、线程、进程等)。
产生数据的模块,就形象地称为生产者;而处理数据的模块,就称为消费者。
二、结构
生产者------》缓冲区-------》消费者
举一个烤肉的例子,假设要去吃烤肉,大致过程如下:
1、烤肉师父会站在一边一直烤肉;
2、再将烤好的肉放在一个盘子中;
3、食客会坐在一边,只要盘子里有肉就会去吃
在这个案例中,生产者----》烤肉师父,缓冲区----》盘子,消费者----》食客负责烤肉。
整个过程中食客与烤肉师父都不是直接打交道的,而是都与盘子进行交互。
烤肉师父烤完了就把肉放在盘子里,盘子充当了一个缓冲区的概念,有东西生产出来就把东西放进去,
盘子也是有大小限制,超过盘子大小就会阻塞生产者生产,等待消费者去消费;当盘子为空的时候 ,即阻塞消费者消费,等待生产者去生产。
编程中阻塞队列(BlockingQueue)即可以实现盘子这个功能。
阻塞队列的特点:
<1> 当队列元素已满的时候,阻塞插入操作.<2> 当队列元素为空的时候,阻塞获取操作。
设置缓冲区的好处:
<1> 解耦,降低生产者与消费者之间的依赖<2> 支持并发。多线程中由于函数调用是同步的(或者叫阻塞的),在消费者的方法没有返回之前,生产者只好一直等在那边。万一消费者处理数据很慢,生产者就会一直阻塞。使用了缓冲区之后,生产者和消费者可以是两个独立的并发主体。生产者把制造出来的数据往缓冲区一丢,就可以再去生产下一个数据。基本上不用依赖消费者的处理速度。
三、例子
下面就是生产者-消费者模式的一个典型的例子:
1、生产者
public class Producer implements Runnable{ private volatile boolean isRunning= true; //内存缓冲区 private BlockingQueue<PCData> queue; //总数,原子操作 private static AtomicInteger count = new AtomicInteger(); private static final int SLEEPTIME=1000; public Producer(BlockingQueue<PCData> queue) { this.queue = queue; } @Override public void run() { PCData data=null; Random r = new Random(); System.out.println("start producer id = "+ Thread .currentThread().getId()); try{ while(isRunning){ Thread.sleep(r.nextInt(SLEEPTIME)); //构造任务数据 data= new PCData(count.incrementAndGet()); System.out.println("data is put into queue "); //提交数据到缓冲区 if(!queue.offer(data,2,TimeUnit.SECONDS)){ System.out.println("faile to put data: "+ data); } } }catch (InterruptedException e){ e.printStackTrace(); Thread.currentThread().interrupt(); } } public void stop(){ isRunning=false; } }
2、消费者
public class Consumer implements Runnable { //缓冲区 private BlockingQueue<PCData> queue; private static final int SLEEPTIME=1000; public Consumer(BlockingQueue<PCData> queue) { this.queue = queue; } @Override public void run() { System.out.println("start Consumer id= "+ Thread .currentThread().getId()); Random r = new Random(); try { //提取任务 while(true){ PCData data= queue.take(); if(null!= data){ //计算平方 int re= data.getData()*data.getData(); System.out.println(MessageFormat.format("{0}*{1}={2}", data.getData(),data.getData(),re)); Thread.sleep(r.nextInt(SLEEPTIME)); } } } catch (InterruptedException e) { e.printStackTrace(); Thread.currentThread().interrupt(); } } }
3、PCData共享数据模型:
public final class PCData { private final int intData; public PCData(int d) { intData=d; } public PCData(String d) { intData=Integer.valueOf(d); } public int getData(){ return intData; } @Override public String toString(){ return "data:"+ intData ; } }
4、Main函数:
public class Main { /** * @param args */ public static void main(String[] args) throws InterruptedException{ //建立缓冲区 BlockingQueue<PCData> queue = new LinkedBlockingDeque<PCData>(10); //建立生产者 Producer producer1 = new Producer(queue); Producer producer2 = new Producer(queue); Producer producer3 = new Producer(queue); //建立消费者 Consumer consumer1 = new Consumer(queue); Consumer consumer2 = new Consumer(queue); Consumer consumer3 = new Consumer(queue); //建立线程池 ExecutorService service = Executors.newCachedThreadPool(); //运行生产者 service.execute(producer1); service.execute(producer2); service.execute(producer3); //运行消费者 service.execute(consumer1); service.execute(consumer2); service.execute(consumer3); Thread.sleep(10*1000); //停止生产者 producer1.stop(); producer2.stop(); producer3.stop(); Thread.sleep(3000); service.shutdown(); } }
这篇关于JAVA设计模式之生产者-消费模式的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!