前面转载了一篇用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;