使用BlockingQuery实现生产者者消费者:考虑并发,解耦。
生产者消费者模式是面向过程的设计模式。
生产者制造数据 ------》 生产者把数据放入缓冲区 -------》 消费者把数据取出缓冲区 --------》相当于消费者处理数据
BlockingQuery学习
支持两个附加操作的 Queue
,这两个操作是:获取元素时等待队列变为非空,以及存储元素时等待空间变得可用。
BlockingQueue 方法以四种形式出现,对于不能立即满足但可能在将来某一时刻可以满足的操作,这四种形式的处理方式不同:第一种是抛出一个异常,第二种是返回一个特殊值(null 或 false,具体取决于操作),第三种是在操作可以成功前,无限期地阻塞当前线程,第四种是在放弃前只在给定的最大时间限制内阻塞。下表中总结了这些方法:
抛出异常 | 特殊值 | 阻塞 | 超时 | |
插入 | add(e) |
offer(e) |
put(e) |
offer(e, time, unit) |
移除 | remove() |
poll() |
take() |
poll(time, unit) |
检查 | element() |
peek() |
不可用 | 不可用 |
BlockingQueue 不接受 null 元素。试图 add、put 或 offer 一个 null 元素时,某些实现会抛出 NullPointerException。null 被用作指示 poll 操作失败的警戒值。
BlockingQueue 可以是限定容量的。它在任意给定时间都可以有一个 remainingCapacity,超出此容量,便无法无阻塞地 put 附加元素。没有任何内部容量约束的 BlockingQueue 总是报告 Integer.MAX_VALUE 的剩余容量。
BlockingQueue 实现主要用于生产者-使用者队列,但它另外还支持 Collection
接口。因此,举例来说,使用 remove(x) 从队列中移除任意一个元素是有可能的。然而,这种操作通常不 会有效执行,只能有计划地偶尔使用,比如在取消排队信息时。
BlockingQueue 实现是线程安全的。所有排队方法都可以使用内部锁或其他形式的并发控制来自动达到它们的目的。然而,大量的 Collection 操作(addAll、containsAll、retainAll 和 removeAll)没有 必要自动执行,除非在实现中特别说明。因此,举例来说,在只添加了 c 中的一些元素后,addAll(c) 有可能失败(抛出一个异常)。
BlockingQueue 实质上不 支持使用任何一种“close”或“shutdown”操作来指示不再添加任何项。这种功能的需求和使用有依赖于实现的倾向。例如,一种常用的策略是:对于生产者,插入特殊的 end-of-stream 或 poison 对象,并根据使用者获取这些对象的时间来对它们进行解释。
生产者code
package com.liruilong.concurrent.Producer_Consuner; import javax.swing.text.StyledEditorKit; import java.util.concurrent.BlockingQueue; /** * @Description : 生产者 * @Author: Liruilong * @Date: 2019/8/22 7:24 */ public class Producer implements Runnable{ private find BlockingQueue<String> queue; public Producer(BlockingQueue<String> queue){ this.queue = queue; } @Override public void run() { try { String temp = "产品:"+Thread.currentThread().getName(); System.out.println("生产产品: "+Thread.currentThread().getName()); queue.put(temp); //队列已满,阻塞队列。 }catch (InterruptedException e){ e.printStackTrace(); } } }
消费者code
package com.liruilong.concurrent.Producer_Consuner; import java.util.concurrent.BlockingQueue; /** * @Description : 消费者 * @Author: Liruilong * @Date: 2019/8/22 7:56 */ public class Consumer implements Runnable{ private find BlockingQueue<String> queue; public Consumer(BlockingQueue<String> queue) { this.queue = queue; } @Override public void run() { try { // 队列为空,阻塞当前线程 String temp = queue.take(); System.out.println("消费产品:" + temp); }catch (InterruptedException e){ e.printStackTrace(); } } }
测试
package com.liruilong.concurrent.Producer_Consuner; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; /** * @Description : 生产者消费者测试 * @Author: Liruilong * @Date: 2019/8/22 8:01 */ public class Test { public static void main(String[] args) { // 一个基于已链接节点的、任选范围的阻塞双端队列。 BlockingQueue<String> query = new LinkedBlockingQueue<>(2); Consumer consumer = new Consumer(query); Producer producer = new Producer(query); for (int i = 0; i < 5; i ++){ new Thread(producer,"Producer" + (i + 1)).start(); new Thread(consumer, "Consumer" + (i + 1)).start(); } } }
jdk1.6API中关于生产者消费者模式书写:
package com.liruilong.concurrent.Producer_Consuner; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingDeque; /** * @Description : * @Author: Liruilong * @Date: 2019/8/22 8:43 */ public class Code { public static void main(String[] args) { new Code().new Setup().main(); } class Producer implements Runnable { private final BlockingQueue queue; Producer(BlockingQueue q) { queue = q; } public void run() { try { while(true) { queue.put(produce()); } } catch (InterruptedException ex) { ex.printStackTrace(); } } Object produce() { System.out.println("生产商品啦!"); return "商品"; } } class Consumer implements Runnable { private final BlockingQueue queue; Consumer(BlockingQueue q) { queue = q; } public void run() { try { while(true) { consume(queue.take()); } } catch (InterruptedException ex) { ex.printStackTrace(); } } void consume(Object x) { System.out.println("商品被消费掉啦!"); } } class Setup { void main() { BlockingQueue q = new LinkedBlockingDeque(4); // 生产者 Producer p = new Producer(q); // 消费者 Consumer c1 = new Consumer(q); Consumer c2 = new Consumer(q); Thread threadProducer = new Thread(p); while ( !threadProducer.isInterrupted()) { // 生产商品 threadProducer.start(); // 消费商品 new Thread(c1).start(); new Thread(c2).start(); threadProducer.interrupt(); } } } }