Design Pattern: Producer Consumer 模式
Producer Consumer模式與 Guarded Suspension 模式 是類似的,只不過Guarded Suspension模式並不限制緩衝區(qū)的長度,Producer Consumer模式假設(shè)所生產(chǎn)的產(chǎn)品放置在一個(gè)長度有限制的緩衝區(qū)(就像是一個(gè)產(chǎn)品桌,它可以擺放的空間是有限的),如果緩衝區(qū)滿了,則生產(chǎn)者必須停止繼續(xù)將產(chǎn)品放到緩衝區(qū)中,直到消費(fèi)者取走了產(chǎn)品而有了空間,而如果緩衝區(qū)中沒有產(chǎn)品,當(dāng)然消費(fèi)者必須等待,直到有新的產(chǎn)品放到緩衝區(qū)中。
一個(gè)簡單的 UML 順序圖如下所示:

簡單來說,Producer Consumer模式就像是加上了雙重防護(hù)與等待的Guarded Suspension模式,而它的兩個(gè)防護(hù)與等待的條件洽好相反,一個(gè)用Java實(shí)現(xiàn)的簡單流程架構(gòu)如下:
以下舉一個(gè)最簡單的:生產(chǎn)者每次生產(chǎn)一個(gè)整數(shù)並放置在桌子上,而消費(fèi)者消耗整數(shù),桌子上一次只能放置一個(gè)整數(shù),如果桌子上已有整數(shù),則生產(chǎn)者等待消費(fèi)者將整數(shù)消耗並通知生產(chǎn)者生產(chǎn)下一個(gè)整數(shù),如果桌子上沒有整數(shù),則消費(fèi)者等待生產(chǎn)者生產(chǎn)整數(shù)並通知消費(fèi)者可以消耗整數(shù)。
生產(chǎn)者會生產(chǎn)10個(gè)整數(shù),而消費(fèi)者會消耗10個(gè)整數(shù),由於桌上只能放置一個(gè)整數(shù),所以每生產(chǎn)一個(gè)就消耗一個(gè)。

文章來源:http://www.aygfsteel.com/jesson2005/articles/111195.html
一個(gè)簡單的 UML 順序圖如下所示:

- ProductTable.java
import java.util.LinkedList;
public class ProductTable {
private LinkedList products = new LinkedList();
public synchronized void addProduct(Product product) {
while(products.size() >= 2) { // 容量限制為 2
try {
wait();
}
catch(InterruptedException e) {}
}
products.addLast(product);
notifyAll();
}
public synchronized Product getProduct() {
while(products.size() <= 0) {
try {
wait();
}
catch(InterruptedException e) {}
}
Product product = (Product) products.removeFirst();
notifyAll();
return product;
}
}
以下舉一個(gè)最簡單的:生產(chǎn)者每次生產(chǎn)一個(gè)整數(shù)並放置在桌子上,而消費(fèi)者消耗整數(shù),桌子上一次只能放置一個(gè)整數(shù),如果桌子上已有整數(shù),則生產(chǎn)者等待消費(fèi)者將整數(shù)消耗並通知生產(chǎn)者生產(chǎn)下一個(gè)整數(shù),如果桌子上沒有整數(shù),則消費(fèi)者等待生產(chǎn)者生產(chǎn)整數(shù)並通知消費(fèi)者可以消耗整數(shù)。
- Producer.java
public class Producer extends Thread {
private ProductTable productTable;
public Producer(ProductTable productTable) {
this.productTable = productTable;
}
public void run() {
System.out.println("Produce integer......");
for(int product = 1; product <= 10; product++) {
try {
// wait for a random time
Thread.sleep((int) Math.random() * 3000);
}
catch(InterruptedException e) {
e.printStackTrace();
}
productTable.setIntProduct(product);
}
}
}
- Consumer.java
public class Consumer extends Thread {
private ProductTable productTable;
public Consumer(ProductTable productTable) {
this.productTable = productTable;
}
public void run() {
for(int i = 1; i <= 10; i++) {
try {
// wait for a random time
Thread.sleep((int) (Math.random() * 3000));
}
catch(InterruptedException e) {
e.printStackTrace();
}
productTable.getProductInt();
}
}
}
生產(chǎn)者將產(chǎn)品放至桌上,而消費(fèi)者將產(chǎn)品從桌上取走,所以桌子是個(gè)維護(hù)是否讓被放置或消耗產(chǎn)品的地方,由它來決定誰必須等待與通知:
- ProductTable.java
public class ProductTable {
private int productInt = -1; // -1 for no product
public synchronized void setIntProduct(int product) {
if(productInt != -1) {
try {
wait();
}
catch(InterruptedException e) {
e.printStackTrace();
}
}
productInt = product;
System.out.println("set (" + product + ")");
notify();
}
public synchronized int getProductInt() {
if(productInt == -1) {
try {
wait();
}
catch(InterruptedException e) {
e.printStackTrace();
}
}
int p = productInt;
System.out.println("Get (" + productInt + ")");
productInt = -1;
notify();
return p;
}
}
生產(chǎn)者會生產(chǎn)10個(gè)整數(shù),而消費(fèi)者會消耗10個(gè)整數(shù),由於桌上只能放置一個(gè)整數(shù),所以每生產(chǎn)一個(gè)就消耗一個(gè)。
文章來源:http://www.aygfsteel.com/jesson2005/articles/111195.html
posted on 2008-09-07 11:06 大石頭 閱讀(191) 評論(0) 編輯 收藏 所屬分類: 多線程