前言
ReentrantLock 类有一个 newCondition()  方法,用于获取 Lock 上的一个条件,还可以多次调用 newCondition() 以获得多个条件,Condition 可用于线程间通信。
ReentrantLock优势(相比synchronized)
| 特性 | 描述 | 
|---|---|
| 中断一个等待获取锁的线程 | lockInterruptibly 方法能够在获得锁的同时保持对中断的响应,当获取到锁的线程被中断时,中断异常会被抛出,同时锁也会被释放 | 
| 给锁加上超时获取时间 | 当在带有时间限制的操作中调用了一个阻塞方法时,它能根据剩余时间来提供一个时限。如果操作不能在指定的时间给出结果,那么就会使程序提前结束。 | 
| 公平性 | 提供一个先进先出的队列,让线程有序等待获取锁 | 
使用Condition实现一个ArrayBlockingQueue
功能包括:
- 如果一个线程调用该类的 
take()获取元素时,若集合为空则使调用线程阻塞。直到有其他线程为集合加入新元素。 - 如果一个线程调用该类的 
put()添加新元素时,若集合满了则使调用线程阻塞。直到有其他线程从集合中获取数据。内部成员以及构造方法
默认使用长度为 10 的数组来维护数据集合。定义了一个锁,并且根据锁的lock.newCondition()创建了两个条件,分别对应集合满和集合空两个条件。 ```java //维护的数据 private final T[] datas; //数据的个数 private int count; //插入取出的索引 private int put_index; private int take_index; 
//锁 private final Lock lock = new ReentrantLock(); //定义两个条件,分别为“集合满”和“集合空” private Condition full = lock.newCondition(); private Condition empty = lock.newCondition();
//提供MyArrayBlockingQueue的构造方法,初始化T[]数据 public MyArrayBlockingQueue() { this(10); }
public MyArrayBlockingQueue(int maxSize) { this.datas = (T[]) new Object[maxSize]; }
<a name="9uSWR"></a>##### put/get方法```javapublic void put(T data){lock.lock();try {if(count == datas.length){//此时集合已经满了System.out.println("集合已满,请等待...");//使调用线程挂起full.await();}//不满则添加新元素datas[put_index++] = data;count++;//此时唤醒等待取数据的线程empty.signalAll();} catch (Exception e) {e.printStackTrace();}finally{lock.unlock();}}public T take(){lock.lock();try {if(count == 0){//此时集合已经空了System.out.println("集合已空,请等待...");//使调用线程挂起empty.await();}//不空则取出最后一个数据take_index = count - 1;T result = datas[take_index--];count--;//此时唤醒等待写数据的线程full.signalAll();return result;} catch (Exception e) {e.printStackTrace();}finally{lock.unlock();}return null;}
put 方法中,如果集合满了,就调用 await() 方法使对应的线程释放锁,并且使调用线程阻塞。直到其他线程调用了 take() 方法,并调用了 full.signalAll() 时,该请求线程会被精准唤醒,重新竞争到锁后,代码继续往下执行。
若集合不满,则添加新元素,并且通过 empty.signalAll() 精准唤醒等待取数据的线程。
参考资料
ReentrantLock的Condition的作用以及使用
《Java并发编程实战》
