前面闡述了實現生產者與消費者問題的一種方式:wait() / notify()方法,本文繼續闡述多線程的經典問題---生產者與消費者的第二種方式:await() / signal()方法。java
await() / signal()方法安全
在JDK5.0以後,Java提供了更加健壯的線程處理機制,包括同步、鎖定、線程池等,它們能夠實現更細粒度的線程控制。await()和signal()就是其中用來作同步的兩種方法,它們的功能基本上和wait() / nofity()相同,徹底能夠取代它們,可是它們和新引入的鎖定機制Lock直接掛鉤,具備更大的靈活性。經過在Lock對象上調用newCondition()方法,將條件變量和一個鎖對象進行綁定,進而控制併發程序訪問競爭資源的安全。多線程
緩衝區(倉庫):併發
import java.util.LinkedList; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class Storage { // 倉庫最大存儲量 private final int MAX_SIZE = 100; // 倉庫存儲的載體 private LinkedList<Object> list = new LinkedList<Object>(); // 鎖 private final Lock lock = new ReentrantLock(); // 倉庫滿的條件變量 private final Condition full = lock.newCondition(); // 倉庫空的條件變量 private final Condition empty = lock.newCondition(); // 生產num個產品 public void produce(int num){ // 得到鎖 lock.lock(); // 若是倉庫剩餘容量不足 while (list.size() + num > MAX_SIZE){ System.out.println("【要生產的產品數量】:" + num + "【庫存量】:" + list.size()+ "暫時不能執行生產任務!"); try{ // 因爲條件不知足,生產阻塞 full.await(); } catch (InterruptedException e){ e.printStackTrace(); } } // 生產條件知足狀況下,生產num個產品 for (int i = 1; i <= num; ++i){ list.add(new Object()); } System.out.println("【已經生產產品數】:" + num + "/t【現倉儲量爲】:" + list.size()); // 喚醒其餘全部線程 full.signalAll(); empty.signalAll(); // 釋放鎖 lock.unlock(); } // 消費num個產品 public void consume(int num) { // 得到鎖 lock.lock(); // 若是倉庫存儲量不足 while (list.size() < num){ System.out.println("【要消費的產品數量】:" + num + "【庫存量】:" + list.size()+ "暫時不能執行生產任務!"); try{ // 因爲條件不知足,消費阻塞 empty.await(); } catch (InterruptedException e){ e.printStackTrace(); } } // 消費條件知足狀況下,消費num個產品 for (int i = 1; i <= num; ++i){ list.remove(); } System.out.println("【已經消費產品數】:" + num + "【現倉儲量爲】:" + list.size()); // 喚醒其餘全部線程 full.signalAll(); empty.signalAll(); // 釋放鎖 lock.unlock(); } // set/get方法 public int getMAX_SIZE() { return MAX_SIZE; } public LinkedList<Object> getList() { return list; } public void setList(LinkedList<Object> list) { this.list = list; } }
生產者:函數
public class Producer extends Thread { // 每次生產的產品數量 private int num; // 所在放置的倉庫 private Storage storage; // 構造函數,設置倉庫 public Producer(Storage storage){ this.storage = storage; } // 線程run函數 public void run(){ produce(num); } // 調用倉庫Storage的生產函數 public void produce(int num){ storage.produce(num); } // get/set方法 public int getNum() { return num; } public void setNum(int num) { this.num = num; } public Storage getStorage() { return storage; } public void setStorage(Storage storage) { this.storage = storage; } }
消費者:測試
public class Consumer extends Thread { // 每次消費的產品數量 private int num; // 所在放置的倉庫 private Storage storage; // 構造函數,設置倉庫 public Consumer(Storage storage){ this.storage = storage; } // 線程run函數 public void run(){ consume(num); } // 調用倉庫Storage的生產函數 public void consume(int num){ storage.consume(num); } // get/set方法 public int getNum() { return num; } public void setNum(int num) { this.num = num; } public Storage getStorage() { return storage; } public void setStorage(Storage storage) { this.storage = storage; } }
測試類:this
public class Test { public static void main(String[] args) { // 倉庫對象 Storage storage = new Storage(); // 生產者對象 Producer p1 = new Producer(storage); Producer p2 = new Producer(storage); Producer p3 = new Producer(storage); Producer p4 = new Producer(storage); Producer p5 = new Producer(storage); Producer p6 = new Producer(storage); Producer p7 = new Producer(storage); // 消費者對象 Consumer c1 = new Consumer(storage); Consumer c2 = new Consumer(storage); Consumer c3 = new Consumer(storage); // 設置生產者產品生產數量 p1.setNum(10); p2.setNum(10); p3.setNum(10); p4.setNum(10); p5.setNum(10); p6.setNum(10); p7.setNum(80); // 設置消費者產品消費數量 c1.setNum(50); c2.setNum(20); c3.setNum(30); // 線程開始執行 c1.start(); c2.start(); c3.start(); p1.start(); p2.start(); p3.start(); p4.start(); p5.start(); p6.start(); p7.start(); } }