阅读 JDK 源码:AQS 对 Condition 的实现

前两篇文章分别介绍了 AQS 框架中的独占模式和共享模式,本篇将介绍 AQS 对 Condition 接口的实现。
在阅读本篇之前,建议先了解 AQS 中的数据结构和独占模式的实现原理

JUC 通过 Lock 和 Condition 两个接口实现管程(Monitor),其中 Lock 用于解决互斥问题,而 Condition 用于解决同步问题,而 AQS 对 Lock 和 Condition 接口的实现提供了一个基础的框架。

本文基于 jdk1.8.0_91

1. Condition 接口

Lock 替代了 synchronized 方法和语句的使用,Condition 替代了 Object 监视器方法的使用。

Condition 实现可以提供不同于 Object 监视器方法的行为和语义,比如受保证的通知排序,或者在执行通知时不需要保持一个锁。
如果某个实现提供了这样特殊的语义,则该实现必须记录这些语义。

方法摘要:

// 造成当前线程在接到信号或被中断之前一直处于等待状态。 
void await() 

// 造成当前线程在接到信号、被中断或到达指定等待时间之前一直处于等待状态。 
boolean await(long time, TimeUnit unit) 

// 造成当前线程在接到信号、被中断或到达指定等待时间之前一直处于等待状态。
long awaitNanos(long nanosTimeout) 

// 造成当前线程在接到信号之前一直处于等待状态。
void awaitUninterruptibly() 

// 造成当前线程在接到信号、被中断或到达指定最后期限之前一直处于等待状态。 
boolean awaitUntil(Date deadline) 

// 唤醒一个等待线程。
void signal() 

// 唤醒所有等待线程。
void signalAll() 

Condition 本质上是一个队列(称为条件队列),线程等待某个条件成立时,在队列中阻塞,直到其他线程检查条件成立后来通知它。
对于同一个锁,只会存在一个同步队列,但是可能会有多个条件队列,只有在使用了 Condition 才会存在条件队列。

AQS 中对条件队列的使用:

当线程获取锁之后,执行 Condition.await() 会释放锁并进入条件队列,阻塞等待直到被其他线程唤醒。
当其他线程执行 Condition.signal() 唤醒当前线程时,当前线程会从条件队列转移到同步队列来等待再次获取锁。
当前线程再一次获取锁之后,需要在 while 循环中判断条件是否成立,若不成立需重新执行 Condition.await() 去等待。

2. Condition 使用

Condition 实例实质上被绑定到一个锁上。要为特定 Lock 实例获得 Condition 实例,请使用其 newCondition() 方法。

Java 官方文档提供 Condition 接口的使用示例:

对于一个有界阻塞数组,当数组非满时才可以往数组中存放数据,否则阻塞;当数据非空时才可以往数组中取元素,否则阻塞。

class BoundedBuffer {
    final Lock lock = new ReentrantLock();
    final Condition notFull = lock.newCondition();
    final Condition notEmpty = lock.newCondition();

    final Object[] items = new Object[100];
    int putptr, takeptr, count;

    // 生产者方法,往数组里面写数据
    public void put(Object x) throws InterruptedException {
        lock.lock();
        try {
            while (count == items.length)
                notFull.await(); // 阻塞直到非满
            items[putptr] = x;
            if (++putptr == items.length) putptr = 0;
            ++count;
            notEmpty.signal(); // 通知非空
        } finally {
            lock.unlock();
        }
    }

    // 消费者方法,从数组里面拿数据
    public Object take() throws InterruptedException {
        lock.lock();
        try {
            while (count == 0)
                notEmpty.await(); // 阻塞直到非空
            Object x = items[takeptr];
            if (++takeptr == items.length) takeptr = 0;
            --count;
            notFull.signal(); // 通知非满
            return x;
        } finally {
            lock.unlock();
        }
    }
}

在 JDK 的实现中,独占模式才可使用 Condition,共享模式不支持 Condition。
因为 AQS 的内部类 ConditionObject 只支持独占模式。

java.util.concurrent.locks.ReentrantLock.Sync#newCondition

final ConditionObject newCondition() {
	return new ConditionObject();
}

java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock#newCondition

public Condition newCondition() {
	return sync.newCondition();
}

java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock#newCondition

/**
 * Throws {@code UnsupportedOperationException} because
 * {@code ReadLocks} do not support conditions.
 *
 * @throws UnsupportedOperationException always
 */
public Condition newCondition() {
	throw new UnsupportedOperationException();
}

3. Condition 等待方法

3.1 Condition#await

代码流程:

  1. 判断线程是否被中断,如果是,直接抛出InterruptedException,否则进入下一步
  2. 将当前线程封装为节点,存入条件队列。
  3. 释放当前线程已获得的全部的锁,若无持有锁则抛异常。
  4. 在条件队列中,阻塞当前节点。
  5. 当前节点从阻塞中被唤醒(signalled or interrupted),则会从条件队列转移到同步队列(被动或主动地)。
  6. 在同步队列中,自旋、阻塞等待获取锁成功。
  7. 判断整个过程中是否发生过中断,进行不同的处理(抛异常 或 重新中断)。

java.util.concurrent.locks.AbstractQueuedSynchronizer.ConditionObject#await()

/**
 * 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>
 */
public final void await() throws InterruptedException {
	if (Thread.interrupted())
		throw new InterruptedException();
	Node node = addConditionWaiter();    // 将当前线程封装成节点存入条件队列
	int savedState = fullyRelease(node); // 释放已经持有的锁(就是在调用 Condition#await 之前持有的 Lock#lock 锁),并返回释放前的锁状态
	int interruptMode = 0;
	while (!isOnSyncQueue(node)) {       // 检查节点是否在同步队列上
		LockSupport.park(this);          // 节点还在条件队列中,则阻塞   
		// 节点从阻塞中被唤醒(condition#signal,Thread#interrupt),检查中断状态,设置中断处理模式
		// 补充:被 condition#signal 唤醒后的线程会从条件队列转移到同步队列(先出队再入队)
		// 补充:若在条件队列中就发生了中断,也会被转移到同步队列(不出队,只入队,见 checkInterruptWhileWaiting -> transferAfterCancelledWait)
		if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)  
			break;                                                    
	}                                                                 
	if (acquireQueued(node, savedState) && interruptMode != THROW_IE) // 在同步队列等待获取资源直到成功,判断设置中断处理模式
		interruptMode = REINTERRUPT;
	if (node.nextWaiter != null)  // clean up if cancelled 
	    // nextWaiter不为空,说明当前节点是由 Thread#interrupt 唤醒的(condition#signal 唤醒阻塞节点会设置nextWaiter为空)
		// 此时当前节点同时存在于同步队列、条件队列上!但是 waitStatus 不是 CONDITION
		// 需要清除条件队列中已取消的节点
		unlinkCancelledWaiters();
	if (interruptMode != 0)
		reportInterruptAfterWait(interruptMode); // 处理中断:抛异常,或者补上中断状态
}

注意:

  1. 线程被唤醒,可能是执行了 Condition#signal(其中执行 LockSupport#unpark 来唤醒条件队列的头节点),也可能是调用了 Thread#interrupt (会更新线程的中断标识)。
  2. 如果是由 Condition#signal 唤醒的,则当前节点被唤醒后,已经位于同步队列。
  3. 如果是由 Thread#interrupt 唤醒的,则当前节点被唤醒后,需要判断是位于同步队列还是条件队列。
    3.1 如果是位于同步队列,说明是先得到 Condition#signal 通知,再被 Thread#interrupt 中断。
    3.2 如果是位于条件队列,说明未得到 Condition#signal 通知就被 Thread#interrupt 中断了,需要自行加入到同步队列中,再从条件队列中移除。
  4. 当前节点从条件队列转移到同步队列的过程中,发生了中断,该节点依旧会在同步队列中自旋、阻塞直到获取锁,再响应中断(抛异常或重新中断)。

3.1.1 addConditionWaiter

将当前线程封装为节点(waitStatus 为 CONDITION),添加到条件队列尾部。
若条件队列不存在则进行初始化,把当前节点作为头节点(不使用 dummy node)。

java.util.concurrent.locks.AbstractQueuedSynchronizer.ConditionObject#addConditionWaiter

/**
 * Adds a new waiter to wait queue.
 * @return its new wait node
 */
private Node addConditionWaiter() {
	Node t = lastWaiter;
	// If lastWaiter is cancelled, clean out. // 清理条件队列中已取消的尾节点
	if (t != null && t.waitStatus != Node.CONDITION) {
		unlinkCancelledWaiters();
		t = lastWaiter;
	}
	Node node = new Node(Thread.currentThread(), Node.CONDITION); // 构建节点,尾插法
	if (t == null)
		firstWaiter = node;
	else
		t.nextWaiter = node;
	lastWaiter = node;
	return node;
}

3.1.2 fullyRelease

释放当前线程已持有的锁/资源,返回释放之前的锁/资源。
若未持有锁,报错。

这里存在 BUG:报错之前,当前线程已经加入到条件队列之中了,会导致条件队列存储无效的节点数据。
应该将是否持有锁的校验提前到 addConditionWaiter 之前,JDK 11 中已修复该问题。

java.util.concurrent.locks.AbstractQueuedSynchronizer#fullyRelease

final int fullyRelease(Node node) { // 释放当前线程已持有的锁
	boolean failed = true;
	try {
		int savedState = getState(); // 获取 volatile 的 state,独占模式下表示当前线程锁持有的全部锁
		if (release(savedState)) {   // 释放全部的锁
			failed = false;
			return savedState;
		} else {
			throw new IllegalMonitorStateException(); // 未持有锁,报错
		}
	} finally {
		if (failed)
			node.waitStatus = Node.CANCELLED;
	}
}

3.1.3 isOnSyncQueue

判断节点是否在同步队列上。

java.util.concurrent.locks.AbstractQueuedSynchronizer#isOnSyncQueue

/**
 * Returns true if a node, always one that was initially placed on
 * a condition queue, is now waiting to reacquire on sync queue.
 * @param node the node
 * @return true if is reacquiring
 */
final boolean isOnSyncQueue(Node node) {
	if (node.waitStatus == Node.CONDITION || node.prev == null)
		return false;
	if (node.next != null) // If has successor, it must be on queue
		return true;
	return findNodeFromTail(node); // 从尾节点向前遍历查找
}

/**
 * Returns true if node is on sync queue by searching backwards from tail.
 * Called only when needed by isOnSyncQueue.
 * @return true if present
 */
private boolean findNodeFromTail(Node node) {
	Node t = tail;
	for (;;) {
		if (t == node)
			return true;
		if (t == null)
			return false;
		t = t.prev;
	}
}

1. 如果 waitStatus == CONDITION 说明一定是位于条件队列上。

从条件队列入队,构造节点的时候默认就为 CONDITION 状态。
将节点从条件队列转移到同步队列,首先会 CAS 设置 waitStatus 状态为 CONDITION,再执行入队操作。

2. node.prev == null 说明一定是位于条件队列上。

同步队列只有头节点符合 node.prev == null,但是同步队列的头节点是 dummy node,其 thread 为空。
也就是说,来调用 isOnSyncQueue 方法且符合 node.prev == null 条件的节点,只可能是位于条件队列上的节点。

3. 如果 node.next != null 说明一定是处于同步队列上。

节点加入同步队列是个复合操作,最后一步是设置 node.next,当 node.next != null 说明入队操作已执行完成。

4. 如果以上都无法判断节点是否位于同步队列,则遍历链表查找节点。

存在 node.prev != null 但是节点还没有完全入队成功的情况,因为入队操作设置 prev -> tail -> next 是非原子操作。
所以需要从 tail 向前遍历,才能准确判断 node 是否位于同步队列上。
调用 findNodeFromTail 方法前,节点一般位于尾节点附近,不会遍历过多节点。

3.1.4 checkInterruptWhileWaiting

阻塞在 Condition#await 的线程被唤醒之后,调用 checkInterruptWhileWaiting 来检查是否是由线程中断唤醒的。

如果是由线程中断唤醒的,需要进一步判断如何处理中断:

  1. THROW_IE:throw new InterruptedException();
  2. REINTERRUPT:Thread.currentThread().interrupt();

java.util.concurrent.locks.AbstractQueuedSynchronizer.ConditionObject#checkInterruptWhileWaiting

/**
 * Checks for interrupt, returning THROW_IE if interrupted
 * before signalled, REINTERRUPT if after signalled, or
 * 0 if not interrupted.
 */
private int checkInterruptWhileWaiting(Node node) {
    // 校验当前线程是否被中断,并清除线程的中断状态
	return Thread.interrupted() ? 
		(transferAfterCancelledWait(node) ? THROW_IE : REINTERRUPT) : 
		0; // 如果线程未被中断,返回0
}

3.1.5 transferAfterCancelledWait

如果阻塞在 Condition#await 的线程是被中断唤醒的,执行 transferAfterCancelledWait 判断发生中断发生时节点所在的位置。
如果是位于条件队列,则将其添加到同步队列,返回 true;否则返回 false。

如何判断中断发生时节点所在的位置?

  1. 已知 Condition#signal 方法会修改状态(CONDITION -> 0),并操作节点从条件队列出队,从同步队列入队。
  2. 如果 Condition#await 执行 CAS 修改状态成功(CONDITION -> 0),说明线程中断发生时 Condition#signal 还没执行,此时节点是位于条件队列,需要将节点加入同步队列。
  3. 如果 Condition#await 执行 CAS 修改状态失败(CONDITION -> 0),说明线程中断发生时 Condition#signal 已经执行,当前线程需要自旋等待 Condition#signal 执行完。

java.util.concurrent.locks.AbstractQueuedSynchronizer#transferAfterCancelledWait

/**
 * Transfers node, if necessary, to sync queue after a cancelled wait.
 * Returns true if thread was cancelled before being signalled.
 *
 * @param node the node
 * @return true if cancelled before the node was signalled
 */
final boolean transferAfterCancelledWait(Node node) {
	if (compareAndSetWaitStatus(node, Node.CONDITION, 0)) { // 通过 CAS 成功与否来判断节点位置
		enq(node); // 如果CAS成功,说明节点是位于条件队列,需要将它添加到同步队列
		return true;
	}
	/*
	 * If we lost out to a signal(), then we can't proceed
	 * until it finishes its enq().  Cancelling during an
	 * incomplete transfer is both rare and transient, so just
	 * spin.
	 */                          // 条件队列上的节点得到通知(Condition#signal)之后,会添加到同步队列中去。
	while (!isOnSyncQueue(node)) // 这里循环检测,直到确认节点已经成功添加到同步队列中。
		Thread.yield();
	return false;
}

3.1.6 unlinkCancelledWaiters

在 Condition#await 方法中,当线程从阻塞中被线程中断唤醒后,判断节点是位于条件队列中,除了将节点加入同步队列之外,还需要将节点从条件队列中移除。

官方的说明:

  1. 持有锁时才可调用该方法。
  2. 当前线程在 Condition#wait 中阻塞,在被 Condition#signal 唤醒之前,由线程中断或等待超时唤醒。此时需要调用该方法清除条件队列中的无效节点。
  3. 尽管该方法会遍历整个队列,但是只有在 Condition#signal 没有执行之前发生中断或取消才会调用。
  4. 该方法会遍历整个条件队列,一次性把所有无效节点都清除掉,当队列中短时间出现大量无效节点时(cancellation storms)可避免多次遍历队列。

java.util.concurrent.locks.AbstractQueuedSynchronizer.ConditionObject#unlinkCancelledWaiters

/**
 * Unlinks cancelled waiter nodes from condition queue.
 * Called only while holding lock. This is called when
 * cancellation occurred during condition wait, and upon
 * insertion of a new waiter when lastWaiter is seen to have
 * been cancelled. This method is needed to avoid garbage
 * retention in the absence of signals. So even though it may
 * require a full traversal, it comes into play only when
 * timeouts or cancellations occur in the absence of
 * signals. It traverses all nodes rather than stopping at a
 * particular target to unlink all pointers to garbage nodes
 * without requiring many re-traversals during cancellation
 * storms.
 */ 
private void unlinkCancelledWaiters() { // 清除条件队列中状态不为CONDITION的节点
	Node t = firstWaiter; // 游标节点,记录当前遍历的节点
	Node trail = null;    // 游标节点,记录遍历过的最后一个有效节点(状态为CONDITION)
	while (t != null) {   // 从条件队列的头节点开始遍历(下面注释用next代表下一个节点)
		Node next = t.nextWaiter;
		if (t.waitStatus != Node.CONDITION) { // 当前t为无效节点
			t.nextWaiter = null;
			if (trail == null)           // 首次遍历到t为有效节点时,才会初始化trail
				firstWaiter = next;      // 设置t.next为新的头节点(下一次循环校验t.next:若t.next无效,则把t.next.next设为新的头节点)
			else
				trail.nextWaiter = next; // 设置trail.next为t.next(把t出队,下一次循环校验t.next:若t.next无效,则把t.next.next设为trail.next)
			if (next == null)
				lastWaiter = trail;      // 设置trail为新的尾节点
		}
		else      // 当前t为有效节点
			trail = t;
		t = next; // 继续遍历t.next
	}
}

3.1.7 reportInterruptAfterWait

Condition#await 执行到最后,从阻塞中被唤醒且重新取得锁,判断 interruptMode != 0,即 Condition#await 整个过程中发生过中断,需要对中断进行统一处理。

具体见设置 interruptMode 的代码:checkInterruptWhileWaiting

  1. 如果在得到通知之前被中断(在条件队列中),返回 THROW_IE
  2. 如果在得到通知之后被中断(在同步队列中),返回 REINTERRUPT

java.util.concurrent.locks.AbstractQueuedSynchronizer.ConditionObject#reportInterruptAfterWait

/**
 * Throws InterruptedException, reinterrupts current thread, or
 * does nothing, depending on mode.
 */
private void reportInterruptAfterWait(int interruptMode)
	throws InterruptedException {
	if (interruptMode == THROW_IE)
		throw new InterruptedException();
	else if (interruptMode == REINTERRUPT)
		selfInterrupt();
}

java.util.concurrent.locks.AbstractQueuedSynchronizer#selfInterrupt

/**
 * Convenience method to interrupt current thread.
 */
static void selfInterrupt() {
	Thread.currentThread().interrupt();
}

3.2 Condition#awaitNanos

在 Condition 条件上阻塞,具有超时时间。

  1. Condition#await:Block until signalled or interrupted.
  2. Condition#awaitNanos:Block until signalled, interrupted, or timed out.

java.util.concurrent.locks.AbstractQueuedSynchronizer.ConditionObject#awaitNanos

/**
 * Implements timed 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, interrupted, or timed out.
 * <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>
 */
public final long awaitNanos(long nanosTimeout)
		throws InterruptedException {
	if (Thread.interrupted())
		throw new InterruptedException();
	Node node = addConditionWaiter();
	int savedState = fullyRelease(node);
	final long deadline = System.nanoTime() + nanosTimeout; // 等待截止的时间戳
	int interruptMode = 0;
	while (!isOnSyncQueue(node)) {
		if (nanosTimeout <= 0L) { // 已超时,检查节点所在位置,判断是否把节点加入同步队列
			transferAfterCancelledWait(node);
			break;
		}
		if (nanosTimeout >= spinForTimeoutThreshold) // 大于时间阈值,进行阻塞;小于时间阈值,进行自旋
			LockSupport.parkNanos(this, nanosTimeout);
		if ((interruptMode = checkInterruptWhileWaiting(node)) != 0) // 从阻塞中唤醒后,检查是否发生中断,如有中断则结束自旋
			break;
		nanosTimeout = deadline - System.nanoTime(); // 剩余等待时间
	}
	if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
		interruptMode = REINTERRUPT;
	if (node.nextWaiter != null)
		unlinkCancelledWaiters();
	if (interruptMode != 0)
		reportInterruptAfterWait(interruptMode);
	return deadline - System.nanoTime(); // 返回剩余的阻塞时间
}

java.util.concurrent.locks.AbstractQueuedSynchronizer#spinForTimeoutThreshold

/**
 * The number of nanoseconds for which it is faster to spin
 * rather than to use timed park. A rough estimate suffices
 * to improve responsiveness with very short timeouts.
 */
static final long spinForTimeoutThreshold = 1000L;

3.3 Condition#awaitUninterruptibly

在 Condition 条件上阻塞,只能被 Condition#signal 唤醒。

  1. Condition#await:Block until signalled or interrupted.
  2. Condition#awaitNanos:Block until signalled, interrupted, or timed out.
  3. Condition#awaitUninterruptibly:Block until signalled.

java.util.concurrent.locks.AbstractQueuedSynchronizer.ConditionObject#awaitUninterruptibly

/**
 * Implements uninterruptible condition wait.
 * <ol>
 * <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.
 * <li> Reacquire by invoking specialized version of
 *      {@link #acquire} with saved state as argument.
 * </ol>
 */
public final void awaitUninterruptibly() {
	Node node = addConditionWaiter();
	int savedState = fullyRelease(node);
	boolean interrupted = false;
	while (!isOnSyncQueue(node)) {
		LockSupport.park(this);
		if (Thread.interrupted())
			interrupted = true;
	}
	if (acquireQueued(node, savedState) || interrupted)
		selfInterrupt();
}

4. Condition 通知方法

4.1 Condition#signal

唤醒在 Condition#await 上等待最久的线程。
把条件队列的头节点出队,把它加入同步队列,并唤醒节点中的线程。
被唤醒的线程从 Condition#await 中醒来后,执行 AbstractQueuedSynchronizer#acquireQueued 等待再次获取锁。

java.util.concurrent.locks.AbstractQueuedSynchronizer.ConditionObject#signal

/**
 * 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}
 */
public final void signal() {
	if (!isHeldExclusively()) // 未持有独占锁,报错
		throw new IllegalMonitorStateException();
	Node first = firstWaiter;
	if (first != null)
		doSignal(first); // 唤醒队首节点(等待时间最长)
}

4.1.1 doSignal

  1. 找到合适的可唤醒的节点,一般是条件队列的头节点,将它从条件队列出队。
  2. 如果头节点是无效节点,则出队直到找到有效节点。

java.util.concurrent.locks.AbstractQueuedSynchronizer.ConditionObject#doSignal

/**
 * 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
 */
private void doSignal(Node first) { // 把条件队列的头节点转移到同步队列
	do {
		if ( (firstWaiter = first.nextWaiter) == null) // 当前节点的后继节点作为新的头节点(出队),若为空,说明队列为空
			lastWaiter = null;
		first.nextWaiter = null;
	} while (!transferForSignal(first) &&    // 把当前节点转移到同步队列(入队),并唤醒节点上的线程(说明条件队列的头节点不是dummy node)
			 (first = firstWaiter) != null); // 转移失败,取最新的firstWaiter,若不为空则重试,若为空,说明队列为空
}

4.1.2 transferForSignal

  1. 修改节点状态:CONDITION -> 0
  2. 加入到同步队列
  3. 唤醒节点

java.util.concurrent.locks.AbstractQueuedSynchronizer#transferForSignal

/**
 * 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)
 */
final boolean transferForSignal(Node node) {
	/*
	 * If cannot change waitStatus, the node has been cancelled. // 条件队列上的节点状态不为CONDITION,说明是已取消
	 */
	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;                         // 补充:node.thread 从 Condition#await 之中被唤醒,后续执行 acquireQueued 尝试获取锁
}

4.2 Condition#signalAll

遍历条件队列,依次唤醒所有节点。
所有节点都会迁移到同步队列等待获取锁。

java.util.concurrent.locks.AbstractQueuedSynchronizer.ConditionObject#signalAll

/**
 * 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}
 */
public final void signalAll() {
	if (!isHeldExclusively())
		throw new IllegalMonitorStateException();
	Node first = firstWaiter;
	if (first != null)
		doSignalAll(first);
}

java.util.concurrent.locks.AbstractQueuedSynchronizer.ConditionObject#doSignalAll

/**
 * Removes and transfers all nodes.
 * @param first (non-null) the first node on condition queue
 */
private void doSignalAll(Node first) {
	lastWaiter = firstWaiter = null;
	do {
		Node next = first.nextWaiter;
		first.nextWaiter = null;
		transferForSignal(first);
		first = next;
	} while (first != null);
}

相关阅读:
阅读 JDK 源码:AQS 中的独占模式
阅读 JDK 源码:AQS 中的共享模式
阅读 JDK 源码:AQS 对 Condition 的实现

作者:Sumkor

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值