前面转载了一篇用BlockingQueue实现生产者消费者模式的文章。文中提到了另外一种实现方式,利用对象的wait以及notifyAll方法。
先贴上代码:
package com.demo.test; import java.util.ArrayList; import java.util.List; public class ProducerConsumer { public static void main(String[] args) { // 建立仓库 MyStack stack = new MyStack(); // 生产者 Producer producer = new Producer(stack); // 消费者 Consumer consumer = new Consumer(stack); // 开始生产 new Thread(producer).start(); // 开始消费 new Thread(consumer).start(); } /** * 产品类 * * @author kk * */ private static class Product { private int id; public Product(int productId) { this.id = productId; } @Override public String toString() { return "product" + id; } } /** * 生产者, 负责生产产品 * * @author kk * */ private static class Producer implements Runnable { private String name = "生产者"; private MyStack myStack; public Producer(MyStack stack) { this.myStack = stack; } @Override public void run() { for (int i = 0; i < 10; i++) { // System.out.println("生产" + i); // 生产产品 Product product = new Product(i); // 入库 myStack.push(product); // 休息下 try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } } } } /** * 消费者,消费产品 * * @author kk * */ private static class Consumer implements Runnable { private String name = "消费者"; private MyStack myStack; public Consumer(MyStack stack) { this.myStack = stack; } @Override public void run() { for (int i = 0; i < 10; i++) { // System.out.println("消费" + i); // 产品出库 Product product = myStack.pop(); try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } } } } /** * 实现自己的仓库,用来存放产品 * * @author kk * */ private static class MyStack { private List<Product> products = new ArrayList<Product>();// 存放产品 /** * 从仓库中获取产品来消费 * * @return */ public synchronized Product pop() { // 如果仓库已经消费空了,那你就等着新品上市吧 if (products.size() == 0) { System.out.println("仓库已经空了,等待生产..."); try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } this.notifyAll();// 通知生产 // 仓库没空,从仓库中拿出一个产品 Product product = products.get(0); products.remove(product); System.out.println("产品出库:" + product); return product; } /** * 将生产者生产的产品入库 * * @param producedProduct */ public synchronized void push(Product producedProduct) { // 如果当前仓库已经满了 if (products.size() >= 5) { System.out.println("仓库已经满啦,没地方放了,快停止生产吧,通知消费者来消费"); try { this.wait();// 停止生产 } catch (InterruptedException e) { e.printStackTrace(); } } this.notifyAll();// 通知消费 // 仓库未满,既然生产了就入库吧 products.add(producedProduct); System.out.println("\t产品入库:" + producedProduct); } } }
仓库已经空了,等待生产... 产品入库:product0 产品出库:product0 产品入库:product1 产品入库:product2 产品出库:product1 产品入库:product3 产品入库:product4 产品入库:product5 产品出库:product2 产品入库:product6 产品入库:product7 产品出库:product3 产品入库:product8 仓库已经满啦,没地方放了,快停止生产吧,通知消费者来消费 产品出库:product4 产品入库:product9 产品出库:product5 产品出库:product6 产品出库:product7 产品出库:product8 产品出库:product9
1,wait()必须在synchronized 函数或者代码块里面,wait会让synchronized函数或者代码块所在线程暂时的停止运行,释放锁,丧失控制权,该线程进入等待,
让其它的线程有机会获得控制权,在条件满足的情况下调用notifyAll()来唤醒正在wait的线程,等待获取cpu时间,获取到后,继续往下执行;
2,生产者Producer和消费者Consumer要共用仓库MyStack;
3,notifyAll()方法是唤醒其他正在等待的线程,并不让出自己的cpu时间,还是会继续运行;
4,仓库空了,消费者wait,通知生产者赶紧生产notifyAll。仓库满了,生产者wait,通知消费者赶紧消费notifyAll;