在上一篇中,咱们了解了下J.U.C的锁的获取与释放的过程,这个过程主要经过在A.Q.S中维持一个等待队列来实现,其中咱们也提到了,在A.Q.S中除了一个等待队列以外,还有一个Condition队列,在了解Condition队列以前,先来看一下Condition是怎么回事: node
The synchronizer framework provides a ConditionObject class for use by synchronizers that maintain exclusive synchronization and conform to the Lock interface. Any number of condition objects may be attached to a lock object, providing classic monitor-style await, signal, and signalAll operations, including those with timeouts, along with some inspection and monitoring methods. 框架
上面的这一段内容摘自Doug Lea的AQS论文,从上面这一段话能够看出,Condition主要是为了在J.U.C框架中提供和Java传统的监视器风格的wait,notify和notifyAll方法相似的功能,那么先来解释一下这三个方法的做用: less
那么Condition是如何实现wait,notify和notifyAll方法的功能呢?咱们接下来看: ide
在Condition中,wait,notify和notifyAll方法分别对应了await,signal和signalAll方法,固然Condition也提供了超时的、不可被中断的await()方法,不过咱们主要仍是看一看await,notify和notifyAll的实现,先看await: 动画
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
publicfinalvoidawait()throwsInterruptedException {
if(Thread.interrupted())
thrownewInterruptedException();
Node node = addConditionWaiter();
intsavedState = fullyRelease(node);
intinterruptMode =0;
while(!isOnSyncQueue(node)) {
LockSupport.park(this);
if((interruptMode = checkInterruptWhileWaiting(node)) !=0)
break;
}
if(acquireQueued(node, savedState) && interruptMode != THROW_IE)
interruptMode = REINTERRUPT;
if(node.nextWaiter !=null)
unlinkCancelledWaiters();
if(interruptMode !=0)
reportInterruptAfterWait(interruptMode);
}
|
整个await的过程以下: ui
能够看到,这个await的操做过程和Object.wait()方法是同样,只不过await()采用了Condition队列的方式实现了Object.wait()的功能。 this
在了解了await方法的实现之后,signal和signalAll方法的实现就相对简单了,先看看signal方法: spa
1
2
3
4
5
6
7
|
publicfinalvoidsignal() {
if(!isHeldExclusively())
thrownewIllegalMonitorStateException();
Node first = firstWaiter;
if(first !=null)
doSignal(first);
}
|
这里先判断当前线程是否持有锁,若是没有持有,则抛出异常,而后判断整个condition队列是否为空,不为空则调用doSignal方法来唤醒线程,看看doSignal方法都干了一些什么: 线程
1
2
3
4
5
6
7
8
|
privatevoiddoSignal(Node first) {
do{
if( (firstWaiter = first.nextWaiter) ==null)
lastWaiter =null;
first.nextWaiter =null;
}while(!transferForSignal(first) &&
(first = firstWaiter) !=null);
}
|
这个while循环的做用就是将firstWaiter往Condition队列的后面移一位,而且唤醒first,看看while循环中tranferForSignal: orm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
finalbooleantransferForSignal(Node node) {
/*
* If cannot change waitStatus, the node has been cancelled.
*/
if (!compareAndSetWaitStatus(node, Node.CONDITION, 0))
return false;
/*
* Splice onto queue and try to set waitStatus of predecessor to
* indicate that thread is (probably) waiting. If cancelled or
* attempt to set waitStatus fails, wake up to resync (in which
* case the waitStatus can be transiently and harmlessly wrong).
*/
Node p = enq(node);
intc = p.waitStatus;
if(c >0|| !compareAndSetWaitStatus(p, c, Node.SIGNAL))
LockSupport.unpark(node.thread);
returntrue;
}
|
这段代码的做用就是修改Node的waitStatus为0,而后将Node插入到等待队列中,而且唤醒Node。
signalAll和signal方法相似,主要的不一样在于它不是调用doSignal方法,而是调用doSignalAll方法:
1
2
3
4
5
6
7
8
9
|
privatevoiddoSignalAll(Node first) {
lastWaiter = firstWaiter =null;
do{
Node next = first.nextWaiter;
first.nextWaiter =null;
transferForSignal(first);
first = next;
}while(first !=null);
}
|
这个方法就至关于把Condition队列中的全部Node所有取出插入到等待队列中去。
在了解了await(),signal()和signalAll方法的实现之后,咱们再来经过一副gif动画来看一看这一个总体的过程: