按照我看源码的进度,条件 condition 是 aqs 的最后一块拼图。

我总结的 aqs 三要素:
state
ownerThread
等待队列

这里没有考虑到 condition,condition 的用法如下

lock.lock();
  condition.await(t);

lock.unlock();

借助 AbstractQueuedSynchronizer.ConditionObject#await(long, java.util.concurrent.TimeUnit)
来分析条件队列,这个方法会挂起线程,一段时间后自动醒来,不需要其他线程唤醒。

await(t) 要做哪些事?

整体来看,要做两件事:
一、释放锁,挂起线程
二、当线程醒来,重新获取锁

细分步骤:

1. 只有持有了锁,才能做 await(t)
2. 把当前线程加入到条件队列中
3. 重置 state 值为 0,并唤醒等待队列中的节点(这个动作其实就是释放锁)
4. 不考虑自旋时间,直接挂起线程 t 时间
5. 等待 t 时间后,线程被 os 唤醒,把线程所在的节点从条件队列取出,放入等待队列,线程需要重新获取锁

// java.util.concurrent.locks.AbstractQueuedSynchronizer.ConditionObject#await(long, java.util.concurrent.TimeUnit)
public final boolean await(long time, TimeUnit unit)
        throws InterruptedException {
    long nanosTimeout = unit.toNanos(time);
    if (Thread.interrupted())
        throw new InterruptedException();
    Node node = addConditionWaiter();
    int savedState = fullyRelease(node);
    final long deadline = System.nanoTime() + nanosTimeout;
    boolean timedout = false;
    int interruptMode = 0;
    while (!isOnSyncQueue(node)) {
        if (nanosTimeout <= 0L) {
            timedout = 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 !timedout;
}

 

posted on 2020-06-30 18:05  偶尔发呆  阅读(169)  评论(0编辑  收藏  举报