[AQS] ArrayBlockingQueue take AQS await 源码分析

1 take堵塞操作 (区分 poll() 非堵塞以及 中间状态 poll(long timeout, TimeUnit unit)) 

// 有异常
public E remove() {
    E x = poll();
    if (x != null)
        return x;
    else
        throw new NoSuchElementException();
}

2 源码分析

public E take() throws InterruptedException {
    final ReentrantLock lock = this.lock;
    lock.lockInterruptibly();
    try {
        while (count == 0)
            notEmpty.await();
        return dequeue();
    } finally {
        lock.unlock();
    }
}

// 有锁进入等待队列
// 有锁进入等待队列
// 有锁进入等待队列
// 有锁进入等待队列
// 有锁进入等待队列

public final void await() throws InterruptedException {
    if (Thread.interrupted())
        throw new InterruptedException();
    Node node = addConditionWaiter(); // Adds a new waiter to wait queue.
    int savedState = fullyRelease(node);  // 消费者释放资源,从clh中移除,唤醒后续节点
    int interruptMode = 0;
    while (!isOnSyncQueue(node)) {  // 不在同步clh 队列,在等待队列
        LockSupport.park(this);     // park
        if ((interruptMode = checkInterruptWhileWaiting(node)) != 0) // 获取通知入队
            break;
    }
    if (acquireQueued(node, savedState) && interruptMode != THROW_IE) // 
        interruptMode = REINTERRUPT;
    if (node.nextWaiter != null) // clean up if cancelled
        unlinkCancelledWaiters();
    if (interruptMode != 0)
        reportInterruptAfterWait(interruptMode);
}

/**
 * Invokes release with current state value; returns saved state.
 * Cancels node and throws exception on failure.
 * @param node the condition node for this wait
 * @return previous sync state
 */
final int fullyRelease(Node node) {
    boolean failed = true;
    try {
        int savedState = getState();  // 获取当前状态 state
        if (release(savedState)) {
            failed = false;
            return savedState;
        } else {
            throw new IllegalMonitorStateException();
        }
    } finally {
        if (failed)
            node.waitStatus = Node.CANCELLED;
    }
}

/**
 * Releases in exclusive mode.  Implemented by unblocking one or
 * more threads if {@link #tryRelease} returns true.
 * This method can be used to implement method {@link Lock#unlock}.
 *
 * @param arg the release argument.  This value is conveyed to
 *        {@link #tryRelease} but is otherwise uninterpreted and
 *        can represent anything you like.
 * @return the value returned from {@link #tryRelease}
 */
public final boolean release(int arg) {
    if (tryRelease(arg)) { // 释放arg个资源
        Node h = head;
        if (h != null && h.waitStatus != 0)
            unparkSuccessor(h);  // 源码 唤醒后续节点
        return true;
    }
    return false;
}

// 释放arg个资源
protected final boolean tryRelease(int releases) {
    int c = getState() - releases;
    if (Thread.currentThread() != getExclusiveOwnerThread())
        throw new IllegalMonitorStateException();
    boolean free = false;
    if (c == 0) { // 独享锁reset
        free = true;   
        setExclusiveOwnerThread(null); // 清空占有者
    }
    setState(c);  // 设置state 
    return free;
}


/**
 * Wakes up node's successor, if one exists.
 *
 * @param node the node
 */
 // 源码 唤醒后续节点
private void unparkSuccessor(Node node) {
    /*
     * If status is negative (i.e., possibly needing signal) try
     * to clear in anticipation of signalling.  It is OK if this
     * fails or if status is changed by waiting thread.
     */
    int ws = node.waitStatus;
    if (ws < 0)
        compareAndSetWaitStatus(node, ws, 0); 

    /*
     * Thread to unpark is held in successor, which is normally
     * just the next node.  But if cancelled or apparently null,
     * traverse backwards from tail to find the actual
     * non-cancelled successor.
     */
    Node s = node.next; // 找到下一个需要被唤醒的节点
    if (s == null || s.waitStatus > 0) {
        s = null;
        for (Node t = tail; t != null && t != node; t = t.prev)
            if (t.waitStatus <= 0)
                s = t;
    }
    if (s != null)
        LockSupport.unpark(s.thread); // 唤醒的节点线程,race state
}

// 释放资源lock ,即从clh队列移除头节点,分析完毕










// 无锁状态等待唤醒--堵塞业务逻辑
// 无锁状态等待唤醒--堵塞业务逻辑
// 无锁状态等待唤醒--堵塞业务逻辑
// 无锁状态等待唤醒--堵塞业务逻辑
// 结下来是park前执行isOnSyncQueue(node)是无锁状态只做查询操作
//  LockSupport.park(this);
public final void await() throws InterruptedException {
    if (Thread.interrupted())
        throw new InterruptedException();
    Node node = addConditionWaiter();
    int savedState = fullyRelease(node); // 已经彻底释放了锁,下面操作是在无锁状态下执行
    int interruptMode = 0;
    // 有可能不需要park就能立即被唤醒运行
    // 可能正在被其他生产者转移到clh队列,node.prev = t;-->compareAndSetTail(t, node)
    while (!isOnSyncQueue(node)) {  // 检测节点是否被移动到了 clh队列上,如果没有,则堵塞park
        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 cancelled
        unlinkCancelledWaiters();
    if (interruptMode != 0)
        reportInterruptAfterWait(interruptMode);
}


/**
 * 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) {
    // node.waitStatus == Node.CONDITION一定是还在等待队列 (volatile int waitStatus;)
    // transferForSignal 先执行更改状态,再去入队
    // node.prev == null 可能是入队中(并发),入队成功就能等待前序节点来唤醒了  
    if (node.waitStatus == Node.CONDITION || node.prev == null) 
        return false;
        
    //  node.next最后set 确保一定入队clh
    if (node.next != null) // If has successor, it must be on queue
        return true;
    /*
     * node.prev can be non-null, but not yet on queue because
     * the CAS to place it on queue can fail. So we have to
     * traverse from tail to make sure it actually made it.  It
     * will always be near the tail in calls to this method, and
     * unless the CAS failed (which is unlikely), it will be
     * there, so we hardly ever traverse much.
     */
    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;
    }
}












// 被激活再次获取锁--执行业务逻辑
// 被激活再次获取锁--执行业务逻辑
// 被激活再次获取锁--执行业务逻辑
// 被激活再次获取锁--执行业务逻辑
// 被激活再次获取锁--执行业务逻辑
// 被激活再次获取锁--执行业务逻辑
// 结下来是clh队列激活--->当前线程 从park中醒来
// 执行 acquireQueued race state
public final void await() throws InterruptedException {
    if (Thread.interrupted())
        throw new InterruptedException();
    Node node = addConditionWaiter();
    int savedState = fullyRelease(node); // 已经彻底释放了锁,下面操作是在无锁状态下执行
    int interruptMode = 0;
    // 有可能不需要park就能立即被唤醒运行
    // 可能正在被其他生产者转移到clh队列,node.prev = t;-->compareAndSetTail(t, node)
    while (!isOnSyncQueue(node)) {  // 检测节点是否被移动到了 clh队列上,如果没有,则堵塞park
        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 cancelled
        unlinkCancelledWaiters();
    if (interruptMode != 0)
        reportInterruptAfterWait(interruptMode);
}

//  Acquires in exclusive mode, ignoring interrupts.  和acquire中的acquireQueued一样,race state
public final void acquire(int arg) {
    if (!tryAcquire(arg) &&
        acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
        selfInterrupt();
}

/**
 * Acquires in exclusive uninterruptible mode for thread already in
 * queue. Used by condition wait methods as well as acquire.
 *
 * @param node the node
 * @param arg the acquire argument
 * @return {@code true} if interrupted while waiting
 */
final boolean acquireQueued(final Node node, int arg) {
    boolean failed = true;
    try {
        boolean interrupted = false;
        for (;;) {
            final Node p = node.predecessor();
            if (p == head && tryAcquire(arg)) {
                setHead(node);
                p.next = null; // help GC
                failed = false;
                return interrupted;
            }
            if (shouldParkAfterFailedAcquire(p, node) &&
                parkAndCheckInterrupt())
                interrupted = true;
        }
    } finally {
        if (failed)
            cancelAcquire(node);
    }
}

3 小结

1 线程take搭配lock,

2 后去不到时,执行await 其中经历了如下:

  •     阶段1: 锁环境下---加入条件队列----释放锁---LockSupport.park // 放弃竞争
  •     阶段2: 被生产者从条件移除,并加入到clh队列-----race时被唤醒-----退出LockSupport.park // 只是入队
  •     阶段3: 再次race获取锁(有可能再次被park,因为在非公平锁可能并发竞争)--竞争到---->继续执行业务逻辑或异常处理 // 去竞争

 

 

 

已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页