Java併發程式設計實戰————Condition
阿新 • • 發佈:2018-12-13
引言
使用Condition實現生產者-消費者模型,並與wait和notify實現的效果相對比。
wait/notify模擬生產者-消費者
面試題:寫一個固定容量同步容器,擁有put和get方法,以及getCount方法能夠支援2個生產執行緒以及10個消費者執行緒的阻塞呼叫。
在《Effective Java》一書中提到:wait()方法()絕大多數情況下都是和while一起使用的。這是因為,當wait()執行完成後,會立刻釋放當前鎖,如果這時其他執行緒立刻獲得鎖並對變數進行操作,會出現資料不一致的情況,使用while可以確保資料不會出現不一致的情況。
public class ProducerConsumer1<T> { final private LinkedList<T> lists = new LinkedList<>(); final private int MAX = 10;// 最多10個元素 private int count = 0; public synchronized void put(T t) { while (lists.size() == this.MAX) {// 想想為什麼用while而不是if try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } lists.add(t); count++; this.notifyAll();// 通知消費者執行緒進行消費 } public synchronized T get() { T t = null; while (lists.size() == 0) { try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } t = lists.removeFirst(); count--; this.notifyAll();// 通知生產者進行生產 return t; } public static void main(String[] args) { ProducerConsumer1<String> c = new ProducerConsumer1<>(); // 啟動消費者執行緒 for (int i = 0; i < 10; i++) { new Thread(() -> { for (int j = 0; j < 5; j++) { System.out.println(c.get()); } }, "c" + i).start(); } try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); } for (int i = 0; i < 2; i++) { new Thread(() -> { for (int j = 0; j < 25; j++) { c.put(Thread.currentThread().getName() + " " + j); } }).start(); } } }
Condition模擬生產者-消費者
使用Lock和Condition來實現類似需求時,可以更加精確的指定哪些執行緒被喚醒,這比notifyAll()效率更高一些。
將上面的程式程式碼進行改寫:
public class ProducerConsumer2<T> { final private LinkedList<T> lists = new LinkedList<>(); final private int MAX = 10; private int count = 0; private Lock lock = new ReentrantLock(); private Condition producer = lock.newCondition(); private Condition consumer = lock.newCondition(); public void put(T t) { try { lock.lock(); while (lists.size() == MAX) { producer.await(); } lists.add(t); ++count; consumer.signalAll(); // 通知消費者執行緒進行消費 } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } public T get() { T t = null; try { lock.lock(); while (lists.size() == 0) { consumer.await(); } t = lists.removeFirst(); count--; producer.signalAll();// 通知生產者進行生產 } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } return t; } public static void main(String[] args) { ProducerConsumer2<String> c = new ProducerConsumer2<>(); // 啟動消費者執行緒 for (int i = 0; i < 10; i++) { new Thread(() -> { for (int j = 0; j < 5; j++) { System.out.println(c.get()); } }, "c" + i).start(); } try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); } for (int i = 0; i < 2; i++) { new Thread(() -> { for (int j = 0; j < 25; j++) { c.put(Thread.currentThread() .getName() + " " + j); } }).start(); } } }