线程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 cancelledunlinkCancelledWaiters();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;}//重点执行transferForSignalwhile (!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



