前面轉載了一篇用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;