Condition条件锁,当线程获得锁之后,可以在指定的Condition上等待或被唤醒
核心函数await:
public final void await() throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
Node node = addConditionWaiter();//将当前线程放到等待队列队尾,类似aqs的head,tail操作,还比较简单就不看了
int savedState = fullyRelease(node);//因为await和signal必须在lock内部执行,所以此时必定持有锁,所以要释放当前线程持有的锁,看下面
int interruptMode = 0;
//这个while很有意思,之前说await必定已经获得到锁,
//那么一定不在aqs的等待队列中(注意condition有2个队列一个是aqs的等待队列,一个是condition维护的wait队列)
//好,如果不在!isOnSyncQueue(node)返回的是true(注意前面的!),
//然后进入循环,线程挂起。
//等到某一天有一个线程调用的signal或signalAll函数,当前线程被唤醒,继续往下执行。
//然后再进入while循环判断,这个时候当前线程会被移到aqs等待队列中(具体在signal函数中以后分析),跳出循环
while (!isOnSyncQueue(node)) {
LockSupport.park(this);
//这里判断在park的时候线程有没有被打断过(即调用interrupte()函数)如果被打断过则跳出
if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
break;
}
//这里其实跟acquire一样先cas一次去尝试获得锁,然后挂起线程
//这里的挂起是等待队列的挂起,不是wait的挂起
if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
interruptMode = REINTERRUPT;
//将cancel的线程从wait队列中移除掉
if (node.nextWaiter != null) // clean up if cancelled
unlinkCancelledWaiters();
if (interruptMode != 0)
//响应打断
reportInterruptAfterWait(interruptMode);
}
final int fullyRelease(Node node) {
boolean failed = true;
try {
int savedState = getState();//获得当前重入锁计数器,当调用acquire()成功的时候会获得锁并将计数器+1,再次调用的时候只增加计数器,具体在https://www.jianshu.com/p/a8e53a694468讲过
if (release(savedState)) {//这里要把所有的计数器都释放掉,这也就表示await是释放锁的,还记得object.wait()是怎么说明的么,同样也会释放锁。笔者在https://www.jianshu.com/p/3748da0ee63c大概写过一些。
failed = false;
return savedState;
} else {
throw new IllegalMonitorStateException();
}
} finally {
if (failed)
node.waitStatus = Node.CANCELLED;
}
}
下一节将signal,await要结合signal一起看可能更清楚