實現思路: 消費與生產都須要獲取隊列的控制權,獲取後都須要斷定隊列的運行容量狀態,只有當知足條件時才能向下執行,並在跳出同步塊時真正釋放控制權。測試
import java.util.LinkedList; import java.util.Queue; public class Storage { private int capacity = 10; private Queue<Object> queue = new LinkedList<Object>(); public void produce(int num) { synchronized (queue) { while (queue.size() + num > capacity) { System.out.println("【要生產的產品數量】:" + num + "\t【庫存量】:" + queue.size() + "\t暫時不能執行生產任務!"); try { queue.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } queue.notifyAll(); // 此時並不會釋放控制權。 只有跳出synchronized塊才釋放 for (int i = 0; i < num; i++) { queue.add(new Object()); } System.out.println("【已經生產產品數】:" + num + "\t【現倉儲量爲】:" + queue.size()); } } public void consume(int num) { synchronized (queue) { while (num > queue.size()) { System.out.println("【要消費的產品數量】:" + num + "\t【庫存量】:" + queue.size() + "\t暫時不能執行消費任務!"); try { queue.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } for (int i = 0; i < num; i++) { queue.remove(); } System.out.println("【已經消費產品數】:" + num + "\t【現倉儲量爲】:" + queue.size()); queue.notifyAll(); } } public static void main(String[] args) { Storage storage = new Storage(); for (int i = 0; i < 5; i++) { final int num = i; new Thread(() -> { while (true) { storage.produce(num); try { Thread.sleep(1000); } catch (Exception e) { e.printStackTrace(); } } }).start(); } for (int i = 0; i < 2; i++) { final int num = i; new Thread(() -> { while (true) { storage.consume(num); try { Thread.sleep(1000); } catch (Exception e) { e.printStackTrace(); } } }).start(); } } }
測試結果:spa
eg.1 : 沒有內部的斷定條件,則只能靠wait()方法的這方控制.net
public class SyncTest { public static void main(String[] args) throws InterruptedException { Object obj = new Object(); new Thread(() -> { while (true) { synchronized (obj) { try { obj.wait(); } catch (Exception e) { e.printStackTrace(); } System.out.println("1"); // 在wait()前或後都行,只是影響第一次輸出的是1或2 } } }).start(); Thread.sleep(100); new Thread(() -> { while (true) { synchronized (obj) { System.out.println("2"); obj.notifyAll(); } try { Thread.sleep(1);//不限制的話,一直輸出的是2 } catch (Exception e) { e.printStackTrace(); } } } ).start(); } }
eg.2 : 若是有內部斷定條件,則兩邊都能有控制code
import java.util.LinkedList; import java.util.Queue; public class SyncTest { public static void main(String[] args) throws InterruptedException { Queue<Object> obj = new LinkedList<Object>(); new Thread(() -> { while (true) { synchronized (obj) { if (obj.size() == 1) { System.out.println("1"); try { obj.wait(); } catch (Exception e) { e.printStackTrace(); } } else { obj.add(new Object()); obj.notify(); } } } }).start(); new Thread(() -> { while (true) { synchronized (obj) { if (obj.size() != 1) { System.out.println("2"); try { obj.wait(); } catch (Exception e) { e.printStackTrace(); } } else { obj.remove(); obj.notify(); } } } }).start(); } }
測試結果:blog