一个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