Java producer-consumer(生产者/消费者模式)
来源:互联网 发布:做数据库有前途吗 编辑:程序博客网 时间:2024/06/06 01:59
生产者消费者模式并不是GOF提出的23种设计模式之一,23种设计模式都是建立在面向对象的基础之上的,但其实面向过程的编程中也有很多高效的编程模式,生产者消费者模式便是其中之一,它是我们编程过程中最常用的一种设计模式。
在java应用中,生产者/消费者模式的实现有以下五种:
1:wait() / nofity()方法是基类Object的两个方法,也就意味着所有Java类都会拥有这两个方法,这样,我们就可以为任何对象实现同步机制。
2.await()和signal()就是其中用来做同步的两种方法,它们的功能基本上和wait() / nofity()相同。
3:BlockingQueue是JDK5.0的新增内容,它是一个已经在内部实现了同步的队列,实现方式采用的是我们第2种await() / signal()方法。
4:PipedOutputStream和PipedInputStream是管道输出流和管道输入流,配合使用可以实现线程间通信。
5:Semaphore除了控制资源的多个副本的并发访问控制,也可以使用二进制信号量来实现类似synchronized关键字和Lock锁的并发访问控制功能。
源码地址:https://github.com/followwwind/javadesign
下面对上面三种进行实现:
/** * @author wind */public interface Storage { /** * 仓库最大存储量 */ int MAX_SIZE = 100; /** * 生产num个产品 * @param num */ void produce(int num); /** * 消费num个产品 * @param num */ void consume(int num);}
1.wait() / nofity()
/** * wait() / nofity()方法是基类Object的两个方法,也就意味着所有Java类都会拥有这两个方法,这样,我们就可以为任何对象实现同步机制。 * wait()方法:当缓冲区已满/空时,生产者/消费者线程停止自己的执行,放弃锁,使自己处于等等状态,让其他线程执行。 * notify()方法:当生产者/消费者向缓冲区放入/取出一个产品时,向其他等待的线程发出可执行的通知,同时放弃锁,使自己处于等待状态。 * @author wind */public class StorageThree implements Storage{ /** * 仓库最大存储量 */ private final int MAX_SIZE = 100; /** * 仓库存储的载体 */ private LinkedList<Object> list = new LinkedList<>(); /** * 生产num个产品 * @param num */ @Override public void produce(int num) { // 同步代码段 synchronized (list) { // 如果仓库剩余容量不足 while (list.size() + num > MAX_SIZE) { System.out.println("【要生产的产品数量】:" + num + "/t【库存量】:" + list.size() + "/t暂时不能执行生产任务!"); try { // 由于条件不满足,生产阻塞 list.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } // 生产条件满足情况下,生产num个产品 for (int i = 1; i <= num; ++i) { list.add(new Object()); } System.out.println("【已经生产产品数】:" + num + "/t【现仓储量为】:" + list.size()); list.notifyAll(); } } /** * 消费num个产品 * @param num */ @Override public void consume(int num) { // 同步代码段 synchronized (list) { // 如果仓库存储量不足 while (list.size() < num) { System.out.println("【要消费的产品数量】:" + num + "/t【库存量】:" + list.size() + "/t暂时不能执行生产任务!"); try { // 由于条件不满足,消费阻塞 list.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } // 消费条件满足情况下,消费num个产品 for (int i = 1; i <= num; ++i) { list.remove(); } System.out.println("【已经消费产品数】:" + num + "/t【现仓储量为】:" + list.size()); list.notifyAll(); } } public LinkedList<Object> getList() { return list; } public void setList(LinkedList<Object> list) { this.list = list; }}
2.await()和signal()
/** * 仓库类Storage实现缓冲区 * 在JDK5.0之后,Java提供了更加健壮的线程处理机制,包括同步、锁定、线程池等,它们可以实现更细粒度的线程控制。 * await()和signal()就是其中用来做同步的两种方法,它们的功能基本上和wait() / nofity()相同, * 完全可以取代它们,但是它们和新引入的锁定机制Lock直接挂钩,具有更大的灵活性。 * 通过在Lock对象上调用newCondition()方法,将条件变量和一个锁对象进行绑定,进而控制并发程序访问竞争资源的安全 * @author wind */public class StorageOne implements Storage { /** * 仓库存储的载体 */ private LinkedList<Object> list = new LinkedList<>(); /** * 锁 */ private final Lock lock = new ReentrantLock(); /** * 仓库满的条件变量 */ private final Condition full = lock.newCondition(); /** * 仓库空的条件变量 */ private final Condition empty = lock.newCondition(); /** * 生产num个产品 * @param num */ @Override public void produce(int num) { // 获得锁 lock.lock(); // 如果仓库剩余容量不足 while (list.size() + num > MAX_SIZE) { System.out.println("【要生产的产品数量】:" + num + "/t【库存量】:" + list.size() + "/t暂时不能执行生产任务!"); try { // 由于条件不满足,生产阻塞 full.await(); } catch (InterruptedException e) { e.printStackTrace(); } } // 生产条件满足情况下,生产num个产品 for (int i = 1; i <= num; ++i) { list.add(new Object()); } System.out.println("【已经生产产品数】:" + num + "/t【现仓储量为】:" + list.size()); // 唤醒其他所有线程 full.signalAll(); empty.signalAll(); // 释放锁 lock.unlock(); } /** * 消费num个产品 * @param num */ @Override public void consume(int num) { // 获得锁 lock.lock(); // 如果仓库存储量不足 while (list.size() < num) { System.out.println("【要消费的产品数量】:" + num + "/t【库存量】:" + list.size() + "/t暂时不能执行生产任务!"); try { // 由于条件不满足,消费阻塞 empty.await(); } catch (InterruptedException e) { e.printStackTrace(); } } // 消费条件满足情况下,消费num个产品 for (int i = 1; i <= num; ++i) { list.remove(); } System.out.println("【已经消费产品数】:" + num + "/t【现仓储量为】:" + list.size()); // 唤醒其他所有线程 full.signalAll(); empty.signalAll(); // 释放锁 lock.unlock(); } public LinkedList<Object> getList() { return list; } public void setList(LinkedList<Object> list) { this.list = list; }}3.BlockingQueue
/** * 仓库类Storage实现缓冲区 * BlockingQueue是JDK5.0的新增内容,它是一个已经在内部实现了同步的队列,实现方式采用的是我们第2种await() / signal()方法。 * 它可以在生成对象时指定容量大小。它用于阻塞操作的是put()和take()方法。 * put()方法:类似于我们上面的生产者线程,容量达到最大时,自动阻塞。 * take()方法:类似于我们上面的消费者线程,容量为0时,自动阻塞。 * @author wind */public class StorageTwo implements Storage { /** * 仓库存储的载体 */ private LinkedBlockingQueue<Object> list = new LinkedBlockingQueue<>(MAX_SIZE); /** * 生产num个产品 * @param num */ @Override public void produce(int num) { // 如果仓库剩余容量为0 if (list.size() == MAX_SIZE) { System.out.println("【库存量】:" + MAX_SIZE + "/t暂时不能执行生产任务!"); } // 生产条件满足情况下,生产num个产品 for (int i = 1; i <= num; ++i) { try { // 放入产品,自动阻塞 list.put(new Object()); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("【现仓储量为】:" + list.size()); } } /** * 消费num个产品 * @param num */ @Override public void consume(int num) { // 如果仓库存储量不足 if (list.size() == 0) { System.out.println("【库存量】:0/t暂时不能执行生产任务!"); } // 消费条件满足情况下,消费num个产品 for (int i = 1; i <= num; ++i) { try { // 消费产品,自动阻塞 list.take(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("【现仓储量为】:" + list.size()); } public LinkedBlockingQueue<Object> getList() { return list; } public void setList(LinkedBlockingQueue<Object> list) { this.list = list; }}
4.消费者类Consumer继承线程类Thread
public class Consumer extends Thread{ /** * 每次消费的产品数量 */ private int num; /** * 所在放置的仓库 */ private Storage storage; /** * 构造函数,设置仓库 * @param storage */ public Consumer(Storage storage) { this.storage = storage; } public Consumer(int num, Storage storage) { this.num = num; this.storage = storage; } /** * 线程run函数 */ @Override public void run() { consume(num); } /** * 调用仓库Storage的生产函数 * @param num */ public void consume(int num) { storage.consume(num); } public int getNum() { return num; } public void setNum(int num) { this.num = num; } public Storage getStorage() { return storage; } public void setStorage(Storage storage) { this.storage = storage; }}5.生产者类Producer继承线程类Thread
public class Producer extends Thread{ /** * 每次生产的产品数量 */ private int num; /** * 所在放置的仓库 */ private Storage storage; /** * 构造函数,设置仓库 * @param storage */ public Producer(Storage storage) { this.storage = storage; } public Producer(int num, Storage storage) { this.num = num; this.storage = storage; } /** * 线程run函数 */ @Override public void run() { produce(num); } /** * 调用仓库Storage的生产函数 * @param num */ public void produce(int num) { storage.produce(num); } public int getNum() { return num; } public void setNum(int num) { this.num = num; } public Storage getStorage() { return storage; } public void setStorage(Storage storage) { this.storage = storage; }}
6.测试
/** * 测试类 * @author wind */public class Test { private static Storage getStorage(String name){ Storage storage = null; switch (name){ //await/signal case "one" : storage = new StorageOne(); break; //blockingqueue case "two" : storage = new StorageTwo(); break; //wait/nofity default: new StorageThree(); break; } return storage; } public static void main(String[] args) { // 仓库对象 Storage storage = getStorage("one"); // 生产者对象和产品生产数量 Producer p1 = new Producer(10, storage); Producer p2 = new Producer(10, storage); Producer p3 = new Producer(10, storage); Producer p4 = new Producer(10, storage); Producer p5 = new Producer(10, storage); Producer p6 = new Producer(10, storage); Producer p7 = new Producer(80, storage); // 消费者对象和产品消费数量 Consumer c1 = new Consumer(50, storage); Consumer c2 = new Consumer(20, storage); Consumer c3 = new Consumer(30, storage); // 线程开始执行 c1.start(); c2.start(); c3.start(); p1.start(); p2.start(); p3.start(); p4.start(); p5.start(); p6.start(); p7.start(); }}
阅读全文
0 0
- Java producer-consumer(生产者/消费者模式)
- 生产者消费者模式(Producer-Consumer)
- Producer-Consumer 生产者,消费者
- Java多线模式-Producer-Consumer模式(生产者、消费者模式)
- 多线程设计模式:Producer-Consumer生产者-消费者模式的C++
- 多线程设计模式——Producer-Consumer生产者消费者模式
- C# Producer Consumer (生产者消费者模式)demo
- C# Producer Consumer (生产者消费者模式)demo
- 生产者消费者问题(Producer-consumer problem)
- 生产者-消费者问题(producer-consumer-problem)
- 生产者-消费者问题(The producer-consumer problem)
- Producer consumer problem - 生产者消费者问题
- Java并发编程实践笔记之—阻塞队列和生产者-消费者模式(Blocking Queues and the Producer-consumer Pattern)
- 第五章 Producer-Consumer(操作系统的生产者消费者模式) 6-3 至 6-7
- 线程问题:生产者(Producer)与消费者(Consumer)
- flex中的Producer(生产者)/Consumer(消费者)
- 生产者-消费者(producer-consumer)问题(二)
- 进程同步--生产者消费者问题(Producer-consumer Problem)
- 我的Linux学习之路(二、配置网络)
- 复杂链表的复制
- RxJava操作符之组合操作符(六)
- Android 异步消息处理机制
- LeetCode 38 Count and Say
- Java producer-consumer(生产者/消费者模式)
- 解释mysql errno121错误原因
- http实现虚拟主机的简单搭建
- System Design——什么是“SystemDesign”问题
- markdown基础语法
- PHPCMS V9任意页面调用分页
- 10.19数论模拟赛
- database is locked
- iOS拨打电话(三种方法)