一個Lock可能關聯着一個或者多個條件,這些條件表如今Condition接口。這些條件(conditions)的目的是容許多個線程控制一個鎖對象而且檢查一個條件是真仍是假,當一個條件爲false時,那麼線程將會被掛起,直到其餘線程喚醒它;Condition接口提供了掛起一個線程和喚醒一個線程的機制;java
在以前的生產者消費者例子中,使用了Lock來同步臨界區,生產者和消費者都只有一個線程;在下面的例子中,生產者和消費者都將有多個線程,當緩衝區滿時,全部的生產者將會被掛起,消費者負責喚醒生產者;當緩衝區空時,消費者將被掛起,生茶者負責喚醒消費者;dom
(1)建立一個大小固定的隊列做爲生產者和消費者的緩衝區;ide
public class MyQueue<T> { private ReentrantLock lock=new ReentrantLock(); private Condition pullConditon=lock.newCondition(); private Condition pushCondition=lock.newCondition(); private int maxSize; private LinkedList<T> list=new LinkedList<>(); public MyQueue(int size) { maxSize=size; } public void push(T t){ lock.lock(); try { while (list.size()== maxSize) { // Current push thread release lock and sleep. pushCondition.await(); } list.push(t); System.out.printf("%s Push Size %d\n", Thread.currentThread().getName(), list.size()); // Week up all pull thread pullConditon.signalAll(); } catch (InterruptedException e) { e.printStackTrace(); }finally { lock.unlock(); } } public T pull(){ T t=null; lock.lock(); try { while (list.size() == 0) { // Current poll thread release lock and sleep. pullConditon.await(); } t=list.poll(); System.out.printf("%s Pull Size %d\n", Thread.currentThread().getName(), list.size()); //Week up all push threads pushCondition.signalAll(); } catch (InterruptedException e) { e.printStackTrace(); }finally { lock.unlock(); } return t; } }(2)建立消費者
public class Consumer implements Runnable{ private MyQueue<Integer> myQueue; public Consumer(MyQueue<Integer> myQueue) { this.myQueue = myQueue; } @Override public void run() { for (int i = 0; i < 50; i++) { myQueue.pull(); try { Random random=new Random(); Thread.sleep(random.nextInt(500)); } catch (InterruptedException e) { e.printStackTrace(); } } } }
public class Producer implements Runnable{ private MyQueue<Integer> myQueue; public Producer(MyQueue<Integer> myQueue) { this.myQueue = myQueue; } @Override public void run() { for (int i = 0; i < 50; i++) { myQueue.push(i); try { Random random=new Random(); Thread.sleep(random.nextInt(500)); } catch (InterruptedException e) { e.printStackTrace(); } } } }(4)Main,建立3個消費者,3個生產者
public class Main { public static void main(String[] args) { MyQueue<Integer> myQueue = new MyQueue<>(100); Thread[] producer = new Thread[3]; Thread[] consumer = new Thread[3]; for (int i=0;i<producer.length;i++) { producer[i] = new Thread(new Producer(myQueue)); } for (int j=0;j<consumer.length;j++) { consumer[j] = new Thread(new Consumer(myQueue)); } for (Thread c : consumer) { c.start(); } for (Thread p : producer) { p.start(); } } }因爲生產者和消費者同樣多,生產者生產的和消費者消費的恰好,因此最終程序會正常結束;
在該例子中,當一個生產者線程佔用了鎖對象,那麼其餘的生產者線程和消費者線程都將被掛起,直到該線程釋放了鎖對象;當隊列滿時,生產者將執行pushConditon接口的await()方法,執行該方法,該線程將會被掛起,而且同時釋放掉鎖對象,從而容許其它線程執行;到消費者執行pushConditon的signalAll()方法時(注意這裏是signalAll()而不是notifyAll()),將會喚醒被全部被pushCondtion掛起的線程,即喚醒生產者;從這個例子生愈來愈感受Java線程機制的強大和靈活;
this