1.Condition为一个接口,其下仅有一个实现类ConditionObject,由于Condition的操作需要获取相关的锁,而AQS则是同步锁的实现基础,所以ConditionObject则定义为AQS的内部类。
public class ConditionObject implements Condition, java.io.Serializable {
}
2.每个Condition对象都包含着一个FIFO队列,该队列是Condition对象通知/等待功能的关键。在队列中每一个节点都包含着一个线程引用,该线程就是在该Condition对象上等待的线程。
public class ConditionObject implements Condition, java.io.Serializable {
private static final long serialVersionUID = 1173984872572414699L;
//头节点
private transient Node firstWaiter;
//尾节点
private transient Node lastWaiter;
public ConditionObject() {
}
/** 省略方法 **/
}
3.调用Condition的await()方法会使当前线程进入等待状态,同时会加入到Condition等待队列同时释放锁。释放锁的时候会将Node从同步CLH队列中移除,并唤醒后续节点。然后检测此节点的线程是否在同步队列上,如果不在,则说明该线程还不具备竞争锁的资格。此时会阻塞当前线程。当从await()方法返回时,当前线程一定是获取了Condition相关连的锁。
4.调用Condition的signal()方法,将会唤醒在等待队列中等待最长时间的节点(条件队列里的首节点),在唤醒节点前,会将节点移到CLH同步队列的尾部。
5.Condition的原理主要涉及到两个队列,一个是AQS中的CLH同步队列,一个是ConditionObject中的等待队列。CLH同步队列是双向队列,ConditionObject中的等待队列为一个单向队列。
CLH同步队列如图。
Condition中的等待队列如图。
6.CLH同步队列全程为Craig, Landin, and Hagersten队列。
7.condition使用示例。
public class ConditionTest {
private LinkedList<String> buffer; //容器
private int maxSize ; //容器最大
private Lock lock;
private Condition fullCondition;
private Condition notFullCondition;
ConditionTest(int maxSize){
this.maxSize = maxSize;
buffer = new LinkedList<String>();
lock = new ReentrantLock();
fullCondition = lock.newCondition();
notFullCondition = lock.newCondition();
}
public void set(String string) throws InterruptedException {
lock.lock(); //获取锁
try {
while (maxSize == buffer.size()){
notFullCondition.await(); //满了,添加的线程进入等待状态
}
buffer.add(string);
fullCondition.signal();
} finally {
lock.unlock(); //记得释放锁
}
}
public String get() throws InterruptedException {
String string;
lock.lock();
try {
while (buffer.size() == 0){
fullCondition.await();
}
string = buffer.poll();
notFullCondition.signal();
} finally {
lock.unlock();
}
return string;
}
}