wait()和notify()實現
/** * 面試題:寫一個固定容量同步容器,擁有put和get方法,以及getCount方法, * 能夠支持2個生產者線程以及10個消費者線程的阻塞調用 * * 使用wait和notify/notifyAll來實現 * * @author mashibing */ package yxxy.c_021; import java.util.LinkedList; import java.util.concurrent.TimeUnit; public class MyContainer1<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() == MAX) { //想想爲什麼用while而不是用if? while會在進行一次判斷 try { this.wait(); //effective java } catch (InterruptedException e) { e.printStackTrace(); } } lists.add(t); ++count; this.notifyAll(); //通知消費者線程進行消費 如果用notify()的話 叫醒的可能還是一個生產者 } 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) { MyContainer1<String> c = new MyContainer1<>(); //啓動消費者線程 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); }, "p" + i).start(); } } }
Lock和Condition實現
/** * 面試題:寫一個固定容量同步容器,擁有put和get方法,以及getCount方法, * 能夠支持2個生產者線程以及10個消費者線程的阻塞調用 * * 使用wait和notify/notifyAll來實現 * * 使用Lock和Condition來實現 * 對比兩種方式,Condition的方式可以更加精確的指定哪些線程被喚醒 * * @author mashibing */ package yxxy.c_021; import java.util.LinkedList; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class MyContainer2<T> { final private LinkedList<T> lists = new LinkedList<>(); final private int MAX = 10; //最多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) { //想想爲什麼用while而不是用if? 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) { MyContainer2<String> c = new MyContainer2<>(); //啓動消費者線程 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); }, "p" + i).start(); } } }
對比兩種方式,Condition的方式可以更加精確的指定哪些線程被喚醒