在實際的軟件開發過程當中,常常會碰到以下場景:某個模塊負責產生數據,這些數據由另外一個模塊來負責處理(此處的模塊是廣義的,能夠是類、函數、線程、進程等)。產生數據的模塊,就形象地稱爲生產者;而處理數據的模塊,就稱爲消費者。 java
單單抽象出生產者和消費者,還夠不上是生產者/消費者模式。該模式還須要有一個緩衝區處於生產者和消費者之間,做爲一箇中介。生產者把數據放入緩衝區,而消費者從緩衝區取出數據。多線程
好處:併發
一、解耦 app
假設生產者和消費者分別是兩個類。若是讓生產者直接調用消費者的某個方法,那麼生產者對於消費者就會產生依賴(也就是耦合)。未來若是消費者的代碼發生變化,可能會影響到生產者。而若是二者都依賴於某個緩衝區,二者之間不直接依賴,耦合也就相應下降了。 ide
二、支持併發函數
使用了生產者/消費者模式以後,生產者和消費者能夠是兩個獨立的併發主體(常見併發類型有進程和線程兩種)。生產者把製造出來的數據往緩衝區一丟,就能夠再去生產下一個數據。基本上不用依賴消費者的處理速度。其實當初這個模式,主要就是用來處理併發問題的。 this
三、支持忙閒不均
緩衝區還有另外一個好處。若是製造數據的速度時快時慢,緩衝區的好處就體現出來了。當數據製造快的時候,消費者來不及處理,未處理的數據能夠暫時存在緩衝區中。等生產者的製造速度慢下來,消費者再慢慢處理掉。 線程
代碼實例:code
/** * 蘋果 * @author Administrator */ public class Apple { private int id; private String descFlat; private String color; public Apple(int id, String descFlat, String color){ this.id = id; this.descFlat = descFlat; this.color = color; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getDescFlat() { return descFlat; } public void setDescFlat(String descFlat) { this.descFlat = descFlat; } public String getColor() { return color; } public void setColor(String color) { this.color = color; } @Override public String toString() { return "Apple [id=" + id + ", descFlat=" + descFlat + ", color=" + color + "]"; } }
import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; /** * 定義籃子 - 多線程模擬實現生產者/消費者模型 * @author Administrator */ public class Basket { BlockingQueue<Apple> queue = new LinkedBlockingQueue<Apple>(); // 生產 蘋果 // put方法放入一個蘋果,若basket滿了,等到basket有位置 public void produce(Apple apple){ try { queue.put(apple); } catch (InterruptedException e) { e.printStackTrace(); } } // 消費 蘋果 // take方法取出一個蘋果,若basket爲空,等到basket有蘋果爲止(獲取並移除此隊列的頭部) public Apple consume(){ try { return queue.take(); } catch (InterruptedException e) { e.printStackTrace(); return null; } } }
/** * 定義生產者 * @author Administrator */ public class Producer implements Runnable{ private int instance; private Basket basket; private boolean flat; public Producer(int instance, Basket basket, boolean flat){ this.instance = instance; this.basket = basket; this.flat = flat; } public void run() { System.out.println("開始初始化生產" + instance + "蘋果"); for(int i=0; i<instance; i++){ Apple apple = new Apple(i,"描述"+i,"紅色"); basket.produce(apple); } System.out.println("初始化生產了" + instance + "蘋果,完畢"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } while(flat){ if(basket.queue.size() < instance){ System.out.println("庫存不足,準備生產了" + instance + "蘋果"); for(int i=0; i<instance; i++){ Apple apple = new Apple(i,"描述"+i,"紅色"); basket.produce(apple); } System.out.println("已經生產了" + instance + "蘋果"); } try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } }
/** * 消費者 * @author Administrator */ public class Consumer implements Runnable{ private int instance; private Basket basket; private boolean flat; public Consumer(int instance, Basket basket, boolean flat){ this.instance = instance; this.basket = basket; this.flat = flat; } public void run() { while(flat){ System.out.println("籃子中蘋果數量:" + basket.queue.size()); if(basket.queue.size() >= instance){ System.out.println("開始消費...."); for(int i=0; i<instance; i++){ Apple apple = basket.consume(); if(apple != null){ System.out.println(apple); } } System.out.println("消費....結束"); }else{ System.out.println("籃子中 蘋果不足..."); try { Thread.sleep(1500); } catch (InterruptedException e) { e.printStackTrace(); } } } } }
public class BlockingQueueTest { public static void main(String[] args) { // 定義一個 籃子 Basket basket = new Basket(); int instance = 5; boolean flat = true; // 初始化 生產者 Producer producer = new Producer(instance, basket,flat); new Thread(producer).start(); // 初始化 消費者 Consumer consumer = new Consumer(instance, basket, flat); new Thread(consumer).start(); } }