public final void signal() {
if (!isHeldExclusively()) // 先判断当前线程是否获得了锁,这个判断比较简单,直接用获得锁的线程和当前线程相比即可
throw new IllegalMonitorStateException();
Node first = firstWaiter; // 拿到 Condition队列上第一个节点
if (first != null)
doSignal(first);
}
private void doSignal(Node first) {
do {// 从 Condition 队列中删除 first 节点
if ((firstWaiter = first.nextWaiter) == null)
lastWaiter = null; // 将 next 节点设置成 null
first.nextWaiter = null;
} while (!transferForSignal(first) && (first = firstWaiter) != null);
}
final boolean transferForSignal(Node node) {
if (!compareAndSetWaitStatus(node, Node.CONDITION, 0))// 更新节点的状态为 0,如果更新失败,只有一种可能就是节点被 CANCELLED了
return false;
Node p = enq(node);// 调用 enq,把当前节点添加到AQS 队列。并且返回返回按当前节点的上一个节点,也就是原tail节点
int ws = p.waitStatus;// 如果上一个节点的状态被取消了, 或者尝试设置个节点的状态为 SIGNAL 失败了(SIGNAL 表示: 他的 next 节点需要停止阻塞),
if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL))
LockSupport.unpark(node.thread); // 唤醒节点上的线程.如果 node 的 prev 节点已经是signal 状态,那么被阻塞的 ThreadA 的唤醒工作由 AQS队列来完成
return true;
}
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) // 如果被取消就清除
unlinkCancelledWaiters();
if (interruptMode != 0) reportInterruptAfterWait(interruptMode);
}
checkInterruptWhileWaiting
private int checkInterruptWhileWaiting(Node node) {
return Thread.interrupted() ? (transferAfterCancelledWait(node) ? THROW_IE : REINTERRUPT) : 0;
}
final boolean transferAfterCancelledWait(Node node) {
// 使用 cas 修改节点状态,如果还能修改成功,说明线程被中断时,signal 还没有被调用。这里有一个知识点,就是线程被唤醒,
// 并不一定是在 java 层面执行了locksupport.unpark,也可能是调用了线程的
// interrupt()方法,这个方法会更新一个中断标识,并且会唤醒处于阻塞状态下的线程。
if (compareAndSetWaitStatus(node, Node.CONDITION, 0)) {
enq(node); // 如果 cas 成功,则把node 添加到 AQS 队列
return true;
} // 如果 cas 失败,则判断当前 node 是否已经在 AQS 队列上,如果不在,则让给其他线程执行 当 node 被触发了 signal 方法时,node 就会被加到 aqs 队列上
while (!isOnSyncQueue(node))// 循环检测 node 是否已经成功添加到 AQS 队列中。如果没有,则通过yield
Thread.yield();
return false;
}