Producer Consumer模式與 Guarded Suspension 模式
是類似的,只不過Guarded Suspension模式並不限制緩衝區的長度,Producer
Consumer模式假設所生產的產品放置在一個長度有限制的緩衝區(就像是一個產品桌,它可以擺放的空間是有限的),如果緩衝區滿了,則生產者必須停止
繼續將產品放到緩衝區中,直到消費者取走了產品而有了空間,而如果緩衝區中沒有產品,當然消費者必須等待,直到有新的產品放到緩衝區中。
一個簡單的 UML 順序圖如下所示:
簡單來說,Producer Consumer模式就像是加上了雙重防護與等待的Guarded Suspension模式,而它的兩個防護與等待的條件洽好相反,一個用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; } }
以下舉一個最簡單的:生產者每次生產一個整數並放置在桌子上,而消費者消耗整數,桌子上一次只能放置一個整數,如果桌子上已有整數,則生產者等待消費者將
整數消耗並通知生產者生產下一個整數,如果桌子上沒有整數,則消費者等待生產者生產整數並通知消費者可以消耗整數。
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); } } }
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(); } } }
生產者將產品放至桌上,而消費者將產品從桌上取走,所以桌子是個維護是否讓被放置或消耗產品的地方,由它來決定誰必須等待與通知:
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; } }
生產者會生產10個整數,而消費者會消耗10個整數,由於桌上只能放置一個整數,所以每生產一個就消耗一個。
|