并发编程(10)生产者/消费者
来源:互联网 发布:淘宝一淘网首页 编辑:程序博客网 时间:2024/06/01 08:07
生产者、消费者设计模式是多线程中经典的设计模式,也是面试常被问到的问题,本章我们将讨论多线程中生产者、消费者的问题。
.1)生产者、消费者问题描述
生产者、消费者设计模式,其实是一种“生产-消费-仓库--产品”模型,它应该具备以下几种特征:
(1)生产者只在仓库未满时生产产品,仓库满则停止生产;
(2)消费者只在仓库有产品余量时消费,仓库空则等待;
(3)当消费者发现仓库没有产品余量时通知生产者去生产;
(4)当生产者生产了产品后通知等待的消费者去消费。
.2)解决方案
(a)使用wait/notify/synchronized方法实现:
首先我们创建一个产品类:
//产品类public class Product {//产品编号private int productId;//产品名称private String productName;public int getProductId() {return productId;}public void setProductId(int productId) {this.productId = productId;}public String getProductName() {return productName;}public void setProductName(String productName) {this.productName = productName;}public Product(int productId, String productName) {super();this.productId = productId;this.productName = productName;}}这个类比较简单,主要创建一个产品类(产品编号、产品名称),我们再来创建一个仓库,进行产品的管理
//仓库类public class WareHouse {// 仓库容量private int size;LinkedList<Product> queue = new LinkedList<Product>();public WareHouse(int size) {this.size = size;}public void createProduct() {try {synchronized (queue) {while (queue.size() == size) {System.out.println("仓库已满");System.out.println("Create_Thread[_"+ Thread.currentThread().getId() + "_]" + "等待");queue.wait();}int i = (int) Thread.currentThread().getId();Product p = new Product(i, "Product__" + i);queue.addFirst(p);System.out.println("Create_Thread[_" + Thread.currentThread().getId()+ "_]:生产了Product[" + i + "," + p.getProductName() + "],当前仓库大小为:"+queue.size());queue.notifyAll();}} catch (InterruptedException e) {e.printStackTrace();}}public void consumeProduct() {try {synchronized (queue) {while (queue.size() == 0) {System.out.println("Consume_Thread[_"+ Thread.currentThread().getId() + "_]" + "等待,当前仓库大小为:"+queue.size());queue.wait();}System.out.println("Consume_Thread[_" + Thread.currentThread().getId()+ "_]:消费了[" + queue.getFirst().getProductId() + ","+ queue.getFirst().getProductName() + "],当前仓库大小为:"+(queue.size()-1));queue.removeFirst();queue.notifyAll();}} catch (InterruptedException e) {e.printStackTrace();}}public int getSize() {return size;}public void setSize(int size) {this.size = size;}public LinkedList<Product> getQueue() {return queue;}public void setQueue(LinkedList<Product> queue) {this.queue = queue;}}仓库,拥有容量属性,并创建一个LinkedList进行product的保存,实现了两个方法,进行产品的创建与消费,再看看我们的生产者、消费者类,
public class Producer extends Thread {private WareHouse house;public Producer(WareHouse house) {this.house = house;}@Overridepublic void run() {house.createProduct();}}消费者:
public class Customer extends Thread {private WareHouse house;public Customer(WareHouse house) {this.house = house;}@Overridepublic void run() {house.consumeProduct();}}测试类:
public class Test {
public static void main(String[] args) {
WareHouse house = new WareHouse(5);
for (int i = 0; i < 10; i++) {
Thread pro1 = new Producer(house);
Thread cus1 = new Customer(house);
cus1.start();
pro1.start();
}
}
}
来看看测试结果:
Consume_Thread[_9_]等待,当前仓库大小为:0Consume_Thread[_11_]等待,当前仓库大小为:0Create_Thread[_10_]:生产了Product[10,Product__10],当前仓库大小为:1Create_Thread[_8_]:生产了Product[8,Product__8],当前仓库大小为:2Consume_Thread[_17_]:消费了[8,Product__8],当前仓库大小为:1Consume_Thread[_11_]:消费了[10,Product__10],当前仓库大小为:0Consume_Thread[_19_]等待,当前仓库大小为:0Consume_Thread[_9_]等待,当前仓库大小为:0Create_Thread[_14_]:生产了Product[14,Product__14],当前仓库大小为:1Consume_Thread[_15_]:消费了[14,Product__14],当前仓库大小为:0Create_Thread[_12_]:生产了Product[12,Product__12],当前仓库大小为:1Consume_Thread[_13_]:消费了[12,Product__12],当前仓库大小为:0Create_Thread[_20_]:生产了Product[20,Product__20],当前仓库大小为:1Consume_Thread[_23_]:消费了[20,Product__20],当前仓库大小为:0Consume_Thread[_9_]等待,当前仓库大小为:0Consume_Thread[_19_]等待,当前仓库大小为:0Create_Thread[_18_]:生产了Product[18,Product__18],当前仓库大小为:1Consume_Thread[_21_]:消费了[18,Product__18],当前仓库大小为:0Create_Thread[_16_]:生产了Product[16,Product__16],当前仓库大小为:1Create_Thread[_24_]:生产了Product[24,Product__24],当前仓库大小为:2Consume_Thread[_19_]:消费了[24,Product__24],当前仓库大小为:1Create_Thread[_26_]:生产了Product[26,Product__26],当前仓库大小为:2Consume_Thread[_9_]:消费了[26,Product__26],当前仓库大小为:1Consume_Thread[_25_]:消费了[16,Product__16],当前仓库大小为:0Create_Thread[_22_]:生产了Product[22,Product__22],当前仓库大小为:1Consume_Thread[_27_]:消费了[22,Product__22],当前仓库大小为:0如上,一个简单的生产者、消费者模型就搭建完毕了,这种方式通过synchronized、wait、notify等方法控制并发,属于线程的基本实现方法,其实java中已经有现成的实现类实现生产者、消费者模式,下面我们来看一下。
(b)BlockingQueue 阻塞队列方式
我们来修改一下仓库类:
public class WareHouse2 {// 仓库容量private int size;private LinkedBlockingQueue<Product> queue;public WareHouse2(int size) {this.size = size;this.queue=new LinkedBlockingQueue<Product>(size);}public void createProduct() {try {int i = (int) Thread.currentThread().getId();Product p = new Product(i, "Product__" + i);queue.put(p);System.out.println("Thread_create>:["+Thread.currentThread().getId()+"],queue_size:"+queue.size());} catch (InterruptedException e) {e.printStackTrace();}}public void consumeProduct() {try {Product pt=queue.take();System.out.println("Thread_consume:["+Thread.currentThread().getId()+"],Product:["+pt.getProductId()+"]");} catch (InterruptedException e) {e.printStackTrace();}}}执行结果:
Thread_create>:[8],queue_size:1Thread_create>:[12],queue_size:2Thread_create>:[16],queue_size:3Thread_consume:[9],Product:[8]Thread_consume:[11],Product:[12]Thread_consume:[13],Product:[16]Thread_create>:[10],queue_size:1Thread_consume:[15],Product:[10]Thread_consume:[19],Product:[14]Thread_create>:[18],queue_size:1Thread_create>:[20],queue_size:2Thread_consume:[25],Product:[18]Thread_create>:[24],queue_size:2Thread_create>:[14],queue_size:2Thread_consume:[17],Product:[20]Thread_consume:[21],Product:[24]Thread_consume:[23],Product:[22]Thread_create>:[22],queue_size:0Thread_consume:[27],Product:[26]Thread_create>:[26],queue_size:0通过源码,可以发现这种方式代码要简洁很多,而且在仓库类中,我们使用的put(),take()方法,当容量达到最大时,put会自动阻塞线程,take方法当容量为0时,也会自动阻塞线程,我们来看看源码
public void put(E e) throws InterruptedException { if (e == null) throw new NullPointerException(); // Note: convention in all put/take/etc is to preset local var // holding count negative to indicate failure unless set. int c = -1; Node<E> node = new Node(e); final ReentrantLock putLock = this.putLock; final AtomicInteger count = this.count; putLock.lockInterruptibly(); try { /* * Note that count is used in wait guard even though it is * not protected by lock. This works because count can * only decrease at this point (all other puts are shut * out by lock), and we (or some other waiting put) are * signalled if it ever changes from capacity. Similarly * for all other uses of count in other wait guards. */ while (count.get() == capacity) { notFull.await(); } enqueue(node); c = count.getAndIncrement(); if (c + 1 < capacity) notFull.signal(); } finally { putLock.unlock(); } if (c == 0) signalNotEmpty(); }
public E take() throws InterruptedException { E x; int c = -1; final AtomicInteger count = this.count; final ReentrantLock takeLock = this.takeLock; takeLock.lockInterruptibly(); try { while (count.get() == 0) { notEmpty.await(); } x = dequeue(); c = count.getAndDecrement(); if (c > 1) notEmpty.signal(); } finally { takeLock.unlock(); } if (c == capacity) signalNotFull(); return x; }我们可以发现,在方法中自动封装了wait(),signal()等同步方法,所以就不需要我们程序自己去处理,从难易程度及安全性准确性来讲,建议大家使用阻塞队列实现生产者、消费者模式。
0 0
- 并发编程(10)生产者/消费者
- 并发编程之生产者消费者
- 并发编程(12)-生产者消费者
- 【Java并发编程】:生产者—消费者模型(含代码)
- java并发编程(十六)--生产者—消费者模型
- Java并发编程 生产者消费者模式
- 【并发编程】生产者与消费者模式
- Java并发编程:生产者-消费者模式
- Java并发编程:生产者消费者模式
- 多线程并发应用(生产者/消费者)
- Java---并发和同步(生产者--消费者)
- 聊聊并发(十)生产者消费者模式
- 聊聊并发(十)生产者消费者模式
- 聊聊并发(十)生产者消费者模式
- 聊聊并发(十)生产者消费者模式
- Java并发编程-10-在锁中使用多条件-生产者消费者问题
- 【Java并发编程】之十三:生产者—消费者模型(含代码)
- 并发编程(一): POSIX 使用互斥量和条件变量实现生产者/消费者问题
- SSRF libcurl protocol wrappers利用分析
- 高性能的智能日志
- 淘宝大秒系统设计详解
- Tricks(七)——list of lists 行和、列和的计算
- IDEA Eclipse Subversion SSH 支持【svn ssh】
- 并发编程(10)生产者/消费者
- Eclipse启动Tomcat错误:
- acm773
- 数据存储——文件存储
- 使用模拟器开发Android应用
- LintCode:在O(1)时间复杂度删除链表节点
- caffe源码简单解析——Layer层
- UI常用控件和属性
- Retrofit2.0使用 很好用