/** * Implements interruptible condition wait. * <ol> * <li> If current thread is interrupted, throw InterruptedException. * <li> Save lock state returned by {@link #getState}. * <li> Invoke {@link #release} with saved state as argument, * throwing IllegalMonitorStateException if it fails. * <li> Block until signalled or interrupted. * <li> Reacquire by invoking specialized version of * {@link #acquire} with saved state as argument. * <li> If interrupted while blocked in step 4, throw InterruptedException. * </ol> */ /** * 调用该方法之后,使当前获取lock的线程进入等待队列, * 如果该线程能够从await()方法返回的话一定是该线程获取了与condition相关联的lock。 */ publicfinalvoidawait()throws InterruptedException { if (Thread.interrupted())//响应中断 thrownew InterruptedException(); // 1. 将当前线程包装成Node,插入到等待队列中尾部; // 只有被signal/signalAll后会使得当前线程从等待队列中移至到同步队列中去 Node node = addConditionWaiter(); // 2. 释放当前线程所占用的lock,在释放的过程中会唤醒同步队列中的下一个节点 int savedState = fullyRelease(node); int interruptMode = 0; while (!isOnSyncQueue(node)) {//退出条件:条件为false或者执行到break // 3. 当前线程进入到等待状态,直到获得lock后才会从await方法返回,或者在等待时被中断会做中断处理 LockSupport.park(this); if ((interruptMode = checkInterruptWhileWaiting(node)) != 0) break; } // 4. 自旋等待获取到同步状态(即获取到lock) // 退出await方法必须是已经获得了condition引用(关联)的lock if (acquireQueued(node, savedState) && interruptMode != THROW_IE) interruptMode = REINTERRUPT; if (node.nextWaiter != null) // clean up if cancelled unlinkCancelledWaiters(); // 5. 处理被中断的情况 if (interruptMode != 0) reportInterruptAfterWait(interruptMode); }
/** * Moves the longest-waiting thread, if one exists, from the * wait queue for this condition to the wait queue for the * owning lock. * * @throws IllegalMonitorStateException if {@link #isHeldExclusively} * returns {@code false} */ publicfinalvoidsignal(){ // 先检测当前线程是否已经获取到了lock,否则抛出异常 if (!isHeldExclusively()) thrownew IllegalMonitorStateException(); // 获取等待队列中的头节点进行处理,将其移动到同步队列并使用LockSupport唤醒节点中的线程 Node first = firstWaiter; if (first != null) doSignal(first); }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
/** * Removes and transfers nodes until hit non-cancelled one or * null. Split out from signal in part to encourage compilers * to inline the case of no waiters. * @param first (non-null) the first node on condition queue */ privatevoiddoSignal(Node first){ do { if ( (firstWaiter = first.nextWaiter) == null) lastWaiter = null; // 将头节点从等待队列中移除 first.nextWaiter = null; // while中transferForSignal方法对头结点做真正的处理 } while (!transferForSignal(first) && (first = firstWaiter) != null); }
/** * Transfers a node from a condition queue onto sync queue. * Returns true if successful. * @param node the node * @return true if successfully transferred (else the node was * cancelled before signal) */ finalbooleantransferForSignal(Node node){ /* * If cannot change waitStatus, the node has been cancelled. * 更新头节点状态为0 */ if (!compareAndSetWaitStatus(node, Node.CONDITION, 0)) returnfalse;
/* * 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)) /** * 移动完成之后唤醒该节点的线程,唤醒后的线程, * 将从await方法中的while循环中退出, * 进而调用同步器的acquireQueued方法加入到获取同步状态的竞争者。 * 成功获取同步状态(或者说锁)之后,被唤醒的线程将从先前调用的await()方法返回, * 此时该线程已经成功地获取了锁。 */ LockSupport.unpark(node.thread); returntrue; }
/** * Moves all threads from the wait queue for this condition to * the wait queue for the owning lock. * * @throws IllegalMonitorStateException if {@link #isHeldExclusively} * returns {@code false} */ publicfinalvoidsignalAll(){ if (!isHeldExclusively()) thrownew IllegalMonitorStateException(); Node first = firstWaiter; if (first != null) doSignalAll(first); }
/** * Removes and transfers all nodes. * @param first (non-null) the first node on condition queue */ privatevoiddoSignalAll(Node first){ lastWaiter = firstWaiter = null; do { Node next = first.nextWaiter; first.nextWaiter = null; transferForSignal(first); first = next; } while (first != null); }