线程1->加锁->释放锁&阻塞->线程2->加锁->唤醒线程1->释放锁->线程1->再次加锁
线程1执行await
public final void await() throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
Node node = addConditionWaiter();
int savedState = fullyRelease(node);
int interruptMode = 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) // clean up if cancelled
unlinkCancelledWaiters();
if (interruptMode != 0)
reportInterruptAfterWait(interruptMode);
}
- Node node = addConditionWaiter();封装一个Condition的Node
- int savedState = fullyRelease(node);保存当前node节点的一个状态,同时更改aqs里面的state和ownerThread的值(还原到最开始无锁的状态),同时要唤醒另外因抢占锁导致入队阻塞的线程Thread1
执行完upark,第二个线程的lock阶段就不会卡住了。就要开始加锁了。
- !isOnSyncQueue(node);判断当前这个node是不是Conditon类型的,如果是Condition类型的Node就要走while代码块的东西。
- LockSupport.park(this);挂起当前线程,这边代码直接卡住
线程2执行signal
Node first = firstWaiter;
doSignal(first);
开始唤醒线程1
private void doSignal(Node first) {
do {
//不用太关心
if ( (firstWaiter = first.nextWaiter) == null)
lastWaiter = null;
first.nextWaiter = null;
}
//重点执行transferForSignal
while (!transferForSignal(first) &&
(first = firstWaiter) != null);
}
final boolean transferForSignal(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);
int ws = p.waitStatus;
if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL))
LockSupport.unpark(node.thread);
return true;
}
- !compareAndSetWaitStatus(node, Node.CONDITION, 0);这个结果一定是false,因为当前这个线程1Node节点的类型就是Condition类型的,因此cas能成功
- Node p = enq(node); enq方法,很熟悉了就是把当前这个Node加入队列中,如果没有队列就创建一个。
- if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL))
LockSupport.unpark(node.thread); 通过判断,把线程1唤醒 - 回到线程1卡住的代码,就会继续往下走,最后把线程1Node设置成一个空的Node当作head Node