주요 제조업체의 선임 JAVA 설계자가 조건 소스 코드를 분석하도록 안내합니다.

주의를 기울이고 길을 잃지 마십시오! 이 기사가 도움이된다면 좋아요와 지원을 잊지 마세요!

1. 조건 정의

Condition은 JUC에서 제공하는 도구 클래스로 제어 스레드가 잠금을 해제 한 다음 잠금을 획득 한 다른 스레드가 깨어나 기 위해 신호 신호를 보낼 때까지 기다립니다
.

  1. 내부 조건은 주로 스레드 노드 노드를로드하는 조건 큐에 의해 구현됩니다.
  2. Condition 메서드 (대기, 신호 등)에 대한 호출은 스레드가 배타적 잠금을 획득했다는 전제에 있어야합니다.
  3. Condition 작동 방법의 전제는 배타적 잠금을 획득하는 것이므로 Condition Queue 내부는 동시성 안전성을 지원하지 않는 단방향 대기열입니다 (이것은 AQS의 Sync Queue와 관련됨).

먼저 공통 데모보기

 

import org.apache.log4j.Logger;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 此demo用于测试 condition
 * Created by xujiankang on 2017/2/8.
 */
public class ConditionTest {

    private static final Logger logger = Logger.getLogger(ConditionTest.class);

    static final Lock lock = new ReentrantLock();
    static final Condition condition = lock.newCondition();

    public static void main(String[] args) throws Exception{

        final Thread thread1 = new Thread("Thread 1 "){
            @Override
            public void run() {
                lock.lock(); // 线程 1获取 lock
                logger.info(Thread.currentThread().getName() + " 正在运行 .....");

                try {
                    Thread.sleep(2 * 1000);
                    logger.info(Thread.currentThread().getName() + " 停止运行, 等待一个 signal ");
                    condition.await(); // 调用 condition.await 进行释放锁, 将当前节点封装成一个 Node 放入 Condition Queue 里面, 等待唤醒
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                logger.info(Thread.currentThread().getName() + " 获取一个 signal, 继续执行 ");
                lock.unlock(); // 释放锁
            }
        };

        thread1.start();  // 线程 1 线运行

        Thread.sleep(1 * 1000);

        Thread thread2 = new Thread("Thread 2 "){
            @Override
            public void run() {
                lock.lock();        // 线程 2获取lock
                logger.info(Thread.currentThread().getName() + " 正在运行.....");
                thread1.interrupt(); // 对线程1 进行中断 看看中断后会怎么样? 结果 线程 1还是获取lock, 并且最后还进行 lock.unlock()操作

                try {
                    Thread.sleep(2 * 1000);
                }catch (Exception e){

                }
                condition.signal(); // 发送唤醒信号 从 AQS 的 Condition Queue 里面转移 Node 到 Sync Queue
                logger.info(Thread.currentThread().getName() + " 发送一个 signal ");
                logger.info(Thread.currentThread().getName() + " 发送 signal 结束");
                lock.unlock(); // 线程 2 释放锁
            }
        };

        thread2.start();

    }


}

전체 실행 단계

  1. 스레드 1이 실행을 시작하고 잠금을 획득 한 다음 2 초 동안 휴면합니다.
  2. 스레드 1이 1 초 동안 휴면하면 스레드 2가 실행되기 시작하지만 스레드 1이 잠금을 획득하므로 기다리십시오.
  3. 스레드 1은 2 초 동안 잠자고 condition.await ()를 호출하여 잠금을 해제하고 스레드 1을 노드에 캡슐화하고 조건의 조건 대기열에 넣습니다. 잠금을 획득 한 다른 스레드가 신호를 주거나 인터럽트 (인터럽트) 할 때까지 기다리십시오. (잠금을 얻으려면 동기화 대기열로 이동할 수 있습니다.)
  4. 스레드 2는 성공적으로 잠금을 획득하고 스레드 1을 인터럽트합니다. 스레드가 인터럽트 된 후 노드는 조건 대기열에서 동기화 대기열로 전송되지만 여전히 스레드 2에 의해 잠금이 획득되므로 노드는 동기화 대기열에 남아 잠금을 획득하기를 기다립니다.
  5. 스레드 2는 2 초 동안 잠을 자고 신호를 사용하여 Condition Queue의 노드를 깨우기 시작했습니다 (이때 스레드 1을 나타내는 노드가 Sync Queue에 도착했습니다).
  6. 스레드 2는 잠금을 해제하고 동기화 큐에서 잠금을 획득하기 위해 대기중인 노드 노드를 깨 웁니다.
  7. 스레드 1이 깨어나 잠금을 획득합니다.
  8. 스레드 1이 잠금을 해제합니다.

의 결과

 

[2017-02-08 22:43:09,557] INFO  Thread 1  (ConditionTest.java:26) - Thread 1  正在运行 .....
[2017-02-08 22:43:11,565] INFO  Thread 1  (ConditionTest.java:30) - Thread 1  停止运行, 等待一个 signal 
[2017-02-08 22:43:11,565] INFO  Thread 2  (ConditionTest.java:48) - Thread 2  正在运行.....
java.lang.InterruptedException
[2017-02-08 22:43:13,566] INFO  Thread 2  (ConditionTest.java:57) - Thread 2  发送一个 signal 
    at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.reportInterruptAfterWait(AbstractQueuedSynchronizer.java:2014)
[2017-02-08 22:43:13,566] INFO  Thread 2  (ConditionTest.java:58) - Thread 2  发送 signal 结束
    at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2048)
[2017-02-08 22:43:13,567] INFO  Thread 1  (ConditionTest.java:35) - Thread 1  获取一个 signal, 继续执行 
    at com.lami.tuomatuo.search.base.concurrent.aqs.ConditionTest$1.run(ConditionTest.java:31)

2. 조건 생성자 수준의 기본 속성

주로 Condition Queue의 헤드 및 테일 노드 (헤드 및 테일 노드는 여기서 초기화 할 필요가 없음)

 

/** First node of condition queue */
/** Condition Queue 里面的头节点 */
private transient Node firstWaiter;
/** Last node of condition queue */
/** Condition Queue 里面的尾节点 */
private transient Node lastWaiter;

/** Creates a new {@code ConditionObject} instance */
/** 构造函数 */
public ConditionObject(){}

3. 조건 큐 인큐 노드 메소드 addConditionWaiter

addConditionWaiter 메서드는 주로 Condition.await를 호출 할 때 현재 노드를 Node로 캡슐화하고 Condition Queue에 추가하는 데 사용됩니다.

Condition Queue에 대한 다음 작업은 동시성을 고려하지 않습니다 (동기화 대기열 대기열은 동시 작업을 지원함), 그 이유는 무엇입니까? 작업 조건은 현재 스레드가 AQS의 독점 잠금을 획득했기 때문입니다. , 따라서 동시성을 고려할 필요가 없습니다.

 

/**
 * Adds a new waiter to wait queue
 * 将当前线程封装成一个 Node 节点 放入大 Condition Queue 里面
 * 大家可以注意到, 下面对 Condition Queue 的操作都没考虑到 并发(Sync Queue 的队列是支持并发操作的), 这是为什么呢? 因为在进行操作 Condition 是当前的线程已经获取了AQS的独占锁, 所以不需要考虑并发的情况
 * @return
 */
private Node addConditionWaiter(){
    Node t = lastWaiter;                                // 1. Condition queue 的尾节点
    // If lastWaiter is cancelled, clean out              // 2.尾节点已经Cancel, 直接进行清除,
                                                          //    这里有1个问题, 1 何时出现t.waitStatus != Node.CONDITION -> 在对线程进行中断时 ConditionObject -> await -> checkInterruptWhileWaiting -> transferAfterCancelledWait "compareAndSetWaitStatus(node, Node.CONDITION, 0)" <- 导致这种情况一般是 线程中断或 await 超时
                                                          //    一个注意点: 当Condition进行 awiat 超时或被中断时, Condition里面的节点是没有被删除掉的, 需要其他 await 在将线程加入 Condition Queue 时调用addConditionWaiter而进而删除, 或 await 操作差不多结束时, 调用 "node.nextWaiter != null" 进行判断而删除 (PS: 通过 signal 进行唤醒时 node.nextWaiter 会被置空, 而中断和超时时不会)
    if(t != null && t.waitStatus != Node.CONDITION){
        unlinkCancelledWaiters();                        // 3. 调用 unlinkCancelledWaiters 对 "waitStatus != Node.CONDITION" 的节点进行删除(在Condition里面的Node的waitStatus 要么是CONDITION(正常), 要么就是 0 (signal/timeout/interrupt))
        t = lastWaiter;                                // 4. 获取最新的 lastWaiter
    }
    Node node = new Node(Thread.currentThread(), Node.CONDITION); // 5. 将线程封装成 node 准备放入 Condition Queue 里面
    if(t == null){
        firstWaiter = node;                           // 6 .Condition Queue 是空的
    }else{
        t.nextWaiter = node;                          // 7. 最加到 queue 尾部
    }
    lastWaiter = node;                                // 8. 重新赋值 lastWaiter
    return node;
}

4. 조건 깨우기 첫 번째 노드 메서드 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
 */
/**
 * 唤醒 Condition Queue 里面的头节点, 注意这里的唤醒只是将 Node 从 Condition Queue 转到 Sync Queue 里面(这时的 Node 也还是能被 Interrupt)
 */
private void doSignal(Node first){
    do{
        if((firstWaiter = first.nextWaiter) == null){ // 1. 将 first.nextWaiter 赋值给 nextWaiter 为下次做准备
            lastWaiter = null;                          // 2. 这时若 nextWaiter == null, 则说明 Condition 为空了, 所以直接置空 lastWaiter
        }
        first.nextWaiter = null;                        // 3.  first.nextWaiter == null 是判断 Node 从 Condition queue 转移到 Sync Queue 里面是通过 signal 还是 timeout/interrupt
    }while(!transferForSignal(first) && (first = firstWaiter) != null); // 4. 调用  transferForSignal将 first 转移到 Sync Queue 里面, 返回不成功的话, 将 firstWaiter 赋值给 first
}

5. 조건 깨우기 모든 노드 메서드 doSignalAll

 

/**
 * Removes and transfers all nodes
 * @param first (non-null) the first node on condition queue
 */
/**
 * 唤醒 Condition Queue 里面的所有的节点
 */
private void doSignalAll(Node first){
    lastWaiter = firstWaiter = null;       // 1. 将 lastWaiter, firstWaiter 置空
    do{
        Node next = first.nextWaiter;        // 2. 初始化下个换新的节点
        first.nextWaiter = null;            // 3.  first.nextWaiter == null 是判断 Node 从 Condition queue 转移到 Sync Queue 里面是通过 signal 还是 timeout/interrupt
        transferForSignal(first);             // 4. 调用  transferForSignal将 first 转移到 Sync Queue 里面
        first = next;                         // 5. 开始换新 next 节点
    }while(first != null);
}

6. 취소 노드 unlinkCancelledWaiters를 삭제하는 조건 방법

일반 노드는 신호에 의해 깨어나 Condition Queue에서 Sync Queue로 전송되며, 인터럽트 또는 대기 시간 초과가 발생하면 노드의 상태가 직접 변경 (CONDITION에서 0으로)되며 Condition을 정리하지 않고 바로 Sync로 전환됩니다. Queue의 노드이므로 다음 기능이 필요합니다.

 

/**
 * http://czj4451.iteye.com/blog/1483264
 *
 * Unlinks cancelled waiter nodes from condition queue
 * Called only while holding lock. This is called when
 * cancellation occured 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 intot play when
 * timeouts or cancellations all nodes rather than stoppping at a
 * particular target to unlink all pointers to garbege nodes
 * without requiring many re-traversals during cancellation
 * storms
 */
/**
 * 在 调用 addConditionWaiter 将线程放入 Condition Queue 里面时 或 awiat 方法获取 差不多结束时 进行清理 Condition queue 里面的因 timeout/interrupt 而还存在的节点
 * 这个删除操作比较巧妙, 其中引入了 trail 节点, 可以理解为traverse整个 Condition Queue 时遇到的最后一个有效的节点
 */
private void unlinkCancelledWaiters(){
    Node t = firstWaiter;
    Node trail = null;
    while(t != null){
        Node next = t.nextWaiter;               // 1. 先初始化 next 节点
        if(t.waitStatus != Node.CONDITION){   // 2. 节点不有效, 在Condition Queue 里面 Node.waitStatus 只有可能是 CONDITION 或是 0(timeout/interrupt引起的)
            t.nextWaiter = null;               // 3. Node.nextWaiter 置空
            if(trail == null){                  // 4. 一次都没有遇到有效的节点
                firstWaiter = next;            // 5. 将 next 赋值给 firstWaiter(此时 next 可能也是无效的, 这只是一个临时处理)
            }else{
                trail.nextWaiter = next;       // 6. next 赋值给 trail.nextWaiter, 这一步其实就是删除节点 t
            }
            if(next == null){                  // 7. next == null 说明 已经 traverse 完了 Condition Queue
                lastWaiter = trail;
            }
        }else{
            trail = t;                         // 8. 将有效节点赋值给 trail
        }
        t = next;
    }
}

이것은 주로 노드 트레일에서 큐 노드의 매우 섬세한 삭제라는 것은 의심의 여지가 없습니다. 트레일 노드는 전체 조건 큐를 통과 할 때 마지막으로 발견 된 유효한 노드로 이해 될 수 있습니다.

7. 조건은 첫 번째 노드 메서드 신호를 깨 웁니다

 

/**
 * 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}
 */
/**
 * 将 Condition queue 的头节点转移到 Sync Queue 里面
 * 在进行调用 signal 时, 当前的线程必须获取了 独占的锁
 */
@Override
public void signal() {
    if(!isHeldExclusively()){       // 1. 判断当前的线程是否已经获取 独占锁
        throw new IllegalMonitorStateException();
    }
    Node first = firstWaiter;
    if(first != null){
        doSignal(first);           // 2. 调用 doSignal 进行转移
    }
}

위의 인터뷰 질문에 대한 답변은 문서 노트에 정리되어 있습니다. 인터뷰에 대한 정보와 인터뷰 Zhenti 최신 2020 컬렉션 제조업체 중 일부 (모두 스크린 샷의 작은 부분을 문서화)에 대한 정보를 수집했습니다. 클릭하여 신호를 입력 할 수 있습니다 . CSDN .

8. 조건 깨우기 모든 노드 메서드 signalAll

 

/**
 * Moves all threads from the wait queue for this condition to
 * the wait queue for the owning lock
 *
 * @throws IllegalMonitorStateException if {@link #isHeldExclusively()}
 *          return {@code false}
 */
/**
 * 将 Condition Queue 里面的节点都转移到 Sync Queue 里面
 */
public final void signalAll(){
    if(!isHeldExclusively()){
        throw new IllegalMonitorStateException();
    }
    Node first = firstWaiter;
    if(first != null){
        doSignalAll(first);
    }
}

9. 잠금을 해제하고 awaitUninterruptibly 메소드를 기다립니다.

awaitUninterruptibly 방법은 인터럽트에 응답하지 않는 방법이다.
전체 프로세스

  1. 현재 스레드를 노드로 캡슐화하고 조건에 추가
  2. 현재 스레드가 소유 한 독점 잠금을 잃었습니다.
  3. 배타적 잠금을 획득 한 다른 스레드의 웨이크 업 대기, 조건 대기열에서 동기화 대기열로 웨이크 업 한 다음 배타적 잠금 획득
  4. 최종적으로 잠금을 획득 한 후 스레드가 깨어나는 방식 (신호 / 인터럽트)에 따라 처리됩니다.

 

/**
 * Implements uninterruptible condition wait
 * <li>
 *     Save lock state return by {@link #getState()}
 * </li>
 *
 * <li>
 *     Invoke {@link #release(int)} with saved state as argument,
 *     throwing IllegalMonitoringStateException if it fails
 *     Block until signalled
 *     Reacquire by invoking specified version of
 *     {@link #acquire(int)} with saved state as argument
 * </li>
 */
/**
 * 不响应线程中断的方式进行 await
 */
public final void awaitUninterruptibly(){
    Node node = addConditionWaiter();       // 1. 将当前线程封装成一个 Node 放入 Condition Queue 里面
    int savedState = fullyRelease(node);   // 2. 释放当前线程所获取的所有的独占锁(PS: 独占的锁支持重入), 等等, 为什么要释放呢? 以为你调用 awaitUninterruptibly 方法的前提就是你已经获取了 独占锁
    boolean interrupted = false;         // 3. 线程中断标识
    while(!isOnSyncQueue(node)){          // 4. 这里是一个 while loop, 调用 isOnSyncQueue 判断当前的 Node 是否已经被转移到 Sync Queue 里面
       LockSupport.park(this);            // 5. 若当前 node 不在 sync queue 里面, 则先 block 一下等待其他线程调用 signal 进行唤醒; (这里若有其他线程对当前线程进行 中断的换, 也能进行唤醒)
        if(Thread.interrupted()){         // 6. 判断这是唤醒是 signal 还是 interrupted(Thread.interrupted()会清楚线程的中断标记, 但没事, 我们有步骤7中的interrupted进行记录)
            interrupted = true;           // 7. 说明这次唤醒是被中断而唤醒的,这个标记若是true的话, 在 awiat 离开时还要 自己中断一下(selfInterrupt), 其他的函数可能需要线程的中断标识
        }
    }
    if(acquireQueued(node, savedState) || interrupted){ // 8. acquireQueued 返回 true 说明线程在 block 的过程中式被 inetrrupt 过(其实 acquireQueued 返回 true 也有可能其中有一次唤醒是 通过 signal)
        selfInterrupt();                 // 9. 自我中断, 外面的线程可以通过这个标识知道, 整个 awaitUninterruptibly 运行过程中 是否被中断过
    }
}

10. 조건 인터럽트 표시

다음 두 가지는 awaitXXX 메서드가 호출 될 때 스레드가 중단되었는지 여부를 추적하는 데 사용됩니다.
주요 차이점은
1 입니다 . REINTERRUPT : 신호 후 스레드가 중단되었음을 나타냅니다 (REINTERRUPT = 재 인터럽트, 다시 중단하면 결국 selfInterrupt가 호출 됨)
. 2. THROW_IE : 신호를 수신하기 전에 중단 된 다음 직접 예외를 발생 함을 나타냅니다 (Throw_IE = 내부 예외 발생).

 

/**
 * For interruptible waits, we need to track whether to throw
 * InterruptedException, if interrupted while blocked on
 * condition, versus reinterrupt current thread, if
 * interrupted while blocked waiting to re-acquire
 */
/**
 * 下面两个是用于追踪 调用 awaitXXX 方法时线程有没有被中断过
 * 主要的区别是
 *      REINTERRUPT: 代表线程是在 signal 后被中断的        (REINTERRUPT = re-interrupt 再次中断 最后会调用 selfInterrupt)
 *      THROW_IE: 代表在接受 signal 前被中断的, 则直接抛出异常 (Throw_IE = throw inner exception)
 */
/** Mode meaning to reinterrupt on exit from wait */
/** 在离开 awaitXX方法, 退出前再次 自我中断 (调用 selfInterrupt)*/
private static final int REINTERRUPT = 1;
/** Mode meaning to throw InterruptedException on exit from wait */
/**  在离开 awaitXX方法, 退出前再次, 以为在 接受 signal 前被中断, 所以需要抛出异常 */
private static final int THROW_IE = -1;

11. 조건 인터럽트 처리 방법

이 방법은 주로 awaitXX 메서드의 wake-up이 인터럽트에 의한 것인지 확인하기위한 것으로, 인터럽트에 의한 경우 Node.js로 전송합니다.

 

/**
 * Checks for interrupt, returning THROW_IE if interrupted
 * before signalled, REINTERRUPT if after signalled, or
 * 0 if not interrupted
 */
/**
 * 检查 在 awaitXX 方法中的这次唤醒是否是中断引起的
 * 若是中断引起的, 则将 Node 从 Condition Queue 转移到 Sync Queue 里面
 * 返回值的区别:
 *      0: 此次唤醒是通过 signal -> LockSupport.unpark
 *      THROW_IE: 此次的唤醒是通过 interrupt, 并且 在 接受 signal 之前
 *      REINTERRUPT: 线程的唤醒是 接受过 signal 而后又被中断
 */
private int checkInterruptWhileWaiting(Node node){
    return Thread.interrupted() ?
            (transferAfterCancelledWait(node) ? THROW_IE : REINTERRUPT) : 0;
}

12. 조건 인터럽트 처리 방법 reportInterruptAfterWait

 

/**
 * Throws InterruptedException, reinterrupts current thread, or
 * does nothing, depending on mode
 */
/**
 * 这个方法是在 awaitXX 方法离开前调用的, 主要是根据
 * interrupMode 判断是抛出异常, 还是自我再中断一下
 */
private void reportInterruptAfterWait(int interrupMode) throws InterruptedException{
    if(interrupMode == THROW_IE){
        throw new InterruptedException();
    }
    else if(interrupMode == REINTERRUPT){
        selfInterrupt();
    }
}

13. 잠금 해제 및 대기 대기 조건 방법

await이 메소드는 인터럽트 요청에 응답하고 인터럽트 요청을 수신 한 후 Condition Queue에서 Sync Queue로 노드를 전송합니다.

 

/**
 * Implements interruptible condition wait
 *
 * <li>
 *     If current thread is interrupted, throw InterruptedException
 *     Save lock state returned by {@link #getState()}
 *     Invoke {@link #release(int)} with saved state as argument,
 *     throwing IllegalMonitorStateException if it fails
 *     Blocking until signalled or interrupted
 *     Reacquire by invoking specifized version of
 *     {@link #acquire(int)} with saved state as argument.
 *     If interrupted while blocked in step 4, throw InterruptedException
 * </li>
 *
 * @throws InterruptedException
 */
/**
 * 支持 InterruptedException 的 await <- 注意这里即使是线程被中断,
 * 还是需要获取了独占的锁后, 再 调用 lock.unlock 进行释放锁
 */
@Override
public final void await() throws InterruptedException {
    if(Thread.interrupted()){                       // 1. 判断线程是否中断
        throw new InterruptedException();
    }
    Node node = addConditionWaiter();               // 2. 将线程封装成一个 Node 放到 Condition Queue 里面, 其中可能有些清理工作
    int savedState = fullyRelease(node);           // 3. 释放当前线程所获取的所有的锁 (PS: 调用 await 方法时, 当前线程是必须已经获取了独占的锁)
    int interruptMode = 0;
    while(!isOnSyncQueue(node)){                  // 4. 判断当前线程是否在 Sync Queue 里面(这里 Node 从 Condtion Queue 里面转移到 Sync Queue 里面有两种可能 (1) 其他线程调用 signal 进行转移 (2) 当前线程被中断而进行Node的转移(就在checkInterruptWhileWaiting里面进行转移))
        LockSupport.park(this);                   // 5. 当前线程没在 Sync Queue 里面, 则进行 block
        if((interruptMode = checkInterruptWhileWaiting(node)) != 0){    // 6. 判断此次线程的唤醒是否因为线程被中断, 若是被中断, 则会在checkInterruptWhileWaiting的transferAfterCancelledWait 进行节点的转移; 返回值 interruptMode != 0
            break;                                                      // 说明此是通过线程中断的方式进行唤醒, 并且已经进行了 node 的转移, 转移到 Sync Queue 里面
        }
    }
    if(acquireQueued(node, savedState) && interruptMode != THROW_IE){ // 7. 调用 acquireQueued在 Sync Queue 里面进行 独占锁的获取, 返回值表明在获取的过程中有没有被中断过
        interruptMode = REINTERRUPT;
    }
    if(node.nextWaiter != null){ // clean up if cancelled       // 8. 通过 "node.nextWaiter != null" 判断 线程的唤醒是中断还是 signal, 因为通过中断唤醒的话, 此刻代表线程的 Node 在 Condition Queue 与 Sync Queue 里面都会存在
        unlinkCancelledWaiters();                                  // 9. 进行 cancelled 节点的清除
    }
    if(interruptMode != 0){                                     // 10. "interruptMode != 0" 代表通过中断的方式唤醒线程
        reportInterruptAfterWait(interruptMode);                // 11. 根据 interruptMode 的类型决定是抛出异常, 还是自己再中断一下
    }
}

14. 잠금을 해제하고 awaitNanos를 기다리는 조건 메소드

awaitNanos는 타임 아웃 기능을 가지고 있으며, 중단이나 타임 아웃에 관계없이 중단에 대응하는 기능을 가지고 있으며, Condition Queue에서 Sync Queue로 노드를 전송합니다.

 

/**
 * Impelemnts timed condition wait
 *
 * <li>
 *     If current thread is interrupted, throw InterruptedException
 *     Save lock state returned by {@link #getState()}
 *     Invoke {@link #release(int)} with saved state as argument,
 *     throwing IllegalMonitorStateException if it fails
 *     Block until aignalled, interrupted, or timed out
 *     Reacquire by invoking specified version of
 *     {@link #acquire(int)} with saved state as argument
 *     If interrupted while blocked in step 4, throw InterruptedException
 * </li>
 */
/**
 * 所有 awaitXX 方法其实就是
 *  0. 将当前的线程封装成 Node 加入到 Condition 里面
 *  1. 丢到当前线程所拥有的 独占锁,
 *  2. 等待 其他获取 独占锁的线程的唤醒, 唤醒从 Condition Queue 到 Sync Queue 里面, 进而获取 独占锁
 *  3. 最后获取 lock 之后, 在根据线程唤醒的方式(signal/interrupt) 进行处理
 *  4. 最后还是需要调用 lock./unlock 进行释放锁
 */
@Override
public final long awaitNanos(long nanosTimeout) throws InterruptedException {
    if(Thread.interrupted()){                                   // 1. 判断线程是否中断
        throw new InterruptedException();
    }
    Node node = addConditionWaiter();                           // 2. 将线程封装成一个 Node 放到 Condition Queue 里面, 其中可能有些清理工作
    int savedState = fullyRelease(node);                       // 3. 释放当前线程所获取的所有的锁 (PS: 调用 await 方法时, 当前线程是必须已经获取了独占的锁)
    final long deadline = System.nanoTime() + nanosTimeout;   // 4. 计算 wait 的截止时间
    int interruptMode = 0;
    while(!isOnSyncQueue(node)){                              // 5. 判断当前线程是否在 Sync Queue 里面(这里 Node 从 Condtion Queue 里面转移到 Sync Queue 里面有两种可能 (1) 其他线程调用 signal 进行转移 (2) 当前线程被中断而进行Node的转移(就在checkInterruptWhileWaiting里面进行转移))
        if(nanosTimeout <= 0L){                               // 6. 等待时间超时(这里的 nanosTimeout 是有可能 < 0),
            transferAfterCancelledWait(node);                 //  7. 调用 transferAfterCancelledWait 将 Node 从 Condition 转移到 Sync Queue 里面
            break;
        }
        if(nanosTimeout >= spinForTimeoutThreshold){      // 8. 当剩余时间 < spinForTimeoutThreshold, 其实函数 spin 比用 LockSupport.parkNanos 更高效
            LockSupport.parkNanos(this, nanosTimeout);       // 9. 进行线程的 block
        }
        if((interruptMode = checkInterruptWhileWaiting(node)) != 0){   // 10. 判断此次线程的唤醒是否因为线程被中断, 若是被中断, 则会在checkInterruptWhileWaiting的transferAfterCancelledWait 进行节点的转移; 返回值 interruptMode != 0
            break;                                                     // 说明此是通过线程中断的方式进行唤醒, 并且已经进行了 node 的转移, 转移到 Sync Queue 里面
        }
        nanosTimeout = deadline - System.nanoTime();                    // 11. 计算剩余时间
    }

    if(acquireQueued(node, savedState) && interruptMode != THROW_IE){ // 12. 调用 acquireQueued在 Sync Queue 里面进行 独占锁的获取, 返回值表明在获取的过程中有没有被中断过
        interruptMode = REINTERRUPT;
    }
    if(node.nextWaiter != null){                                    // 13. 通过 "node.nextWaiter != null" 判断 线程的唤醒是中断还是 signal, 因为通过中断唤醒的话, 此刻代表线程的 Node 在 Condition Queue 与 Sync Queue 里面都会存在
        unlinkCancelledWaiters();                                      // 14. 进行 cancelled 节点的清除
    }
    if(interruptMode != 0){                                           // 15. "interruptMode != 0" 代表通过中断的方式唤醒线程
        reportInterruptAfterWait(interruptMode);                      // 16. 根据 interruptMode 的类型决定是抛出异常, 还是自己再中断一下
    }
    return deadline - System.nanoTime();                            // 17 这个返回值代表是 通过 signal 还是 超时
}

15. 잠금을 해제하고 대기하는 조건 awaitUntil 메소드

 

/**
 * Implements absolute timed condition wait
 * <li>
 *     If current thread is interrupted, throw InterruptedException
 *     Save lock state returned by {@link #getState()}
 *     Invoke {@link #release(int)} with saved state as argument,
 *     throwing IllegalMonitorStateException if it fails
 *     Block until signalled, interrupted, or timed out
 *     Reacquire by invoking specialized version of
 *     {@link #acquire(int)} with saved state as argument
 *     if interrupted while blocked in step 4, throw InterruptedException
 *     If timeed out while blocked in step 4, return false, else true
 * </li>
 */
/**
 * 所有 awaitXX 方法其实就是
 *  0. 将当前的线程封装成 Node 加入到 Condition 里面
 *  1. 丢到当前线程所拥有的 独占锁,
 *  2. 等待 其他获取 独占锁的线程的唤醒, 唤醒从 Condition Queue 到 Sync Queue 里面, 进而获取 独占锁
 *  3. 最后获取 lock 之后, 在根据线程唤醒的方式(signal/interrupt) 进行处理
 *  4. 最后还是需要调用 lock./unlock 进行释放锁
 *
 *  awaitUntil 和 awaitNanos 差不多
 */
@Override
public boolean awaitUntil(Date deadline) throws InterruptedException {
    long abstime = deadline.getTime();                                      // 1. 判断线程是否中断
    if(Thread.interrupted()){
        throw new InterruptedException();
    }
    Node node = addConditionWaiter();                                       // 2. 将线程封装成一个 Node 放到 Condition Queue 里面, 其中可能有些清理工作
    int savedState = fullyRelease(node);                                   // 3. 释放当前线程所获取的所有的锁 (PS: 调用 await 方法时, 当前线程是必须已经获取了独占的锁)
    boolean timeout = false;
    int interruptMode = 0;
    while(!isOnSyncQueue(node)){                                           // 4. 判断当前线程是否在 Sync Queue 里面(这里 Node 从 Condtion Queue 里面转移到 Sync Queue 里面有两种可能 (1) 其他线程调用 signal 进行转移 (2) 当前线程被中断而进行Node的转移(就在checkInterruptWhileWaiting里面进行转移))
        if(System.currentTimeMillis() > abstime){                          // 5. 计算是否超时
            timeout = transferAfterCancelledWait(node);                    //  6. 调用 transferAfterCancelledWait 将 Node 从 Condition 转移到 Sync Queue 里面
            break;
        }
        LockSupport.parkUntil(this, abstime);                              // 7. 进行 线程的阻塞
        if((interruptMode = checkInterruptWhileWaiting(node)) != 0){       // 8. 判断此次线程的唤醒是否因为线程被中断, 若是被中断, 则会在checkInterruptWhileWaiting的transferAfterCancelledWait 进行节点的转移; 返回值 interruptMode != 0
            break;                                                         // 说明此是通过线程中断的方式进行唤醒, 并且已经进行了 node 的转移, 转移到 Sync Queue 里面
        }
    }

    if(acquireQueued(node, savedState) && interruptMode != THROW_IE){   // 9. 调用 acquireQueued在 Sync Queue 里面进行 独占锁的获取, 返回值表明在获取的过程中有没有被中断过
        interruptMode = REINTERRUPT;
    }
    if(node.nextWaiter != null){                                       // 10. 通过 "node.nextWaiter != null" 判断 线程的唤醒是中断还是 signal, 因为通过中断唤醒的话, 此刻代表线程的 Node 在 Condition Queue 与 Sync Queue 里面都会存在
        unlinkCancelledWaiters();                                         // 11. 进行 cancelled 节点的清除
    }
    if(interruptMode != 0){                                             // 12. "interruptMode != 0" 代表通过中断的方式唤醒线程
        reportInterruptAfterWait(interruptMode);                        // 13. 根据 interruptMode 的类型决定是抛出异常, 还是自己再中断一下
    }

    return !timeout;                                                   // 13. 返回是否通过 interrupt 进行线程的唤醒
}

16. Condition의 계측 방법

 

/**
 * Returns true if this condition was created by the given
 * synchronization object
 */
/**判断当前 condition 是否获取 独占锁 */
final boolean isOwnedBy(KAbstractOwnableSynchronizer sync){
    return sync == KAbstractQueuedSynchronizer.this;
}

/**
 * Quires whether any threads are waiting on this condition
 * Implements {@link KAbstractOwnableSynchronizer#"hasWaiters(ConditionObject)}
 *
 * @return {@code true} if there are any waiting threads
 * @throws IllegalMonitorStateException if {@link #isHeldExclusively()}
 *          returns {@code false}
 */
/**
 * 查看 Condition Queue 里面是否有 CONDITION 的节点
 */
protected final boolean hasWaiters(){
    if(!isHeldExclusively()){
        throw new IllegalMonitorStateException();
    }
    for(Node w = firstWaiter; w != null; w = w.nextWaiter ){
        if(w.waitStatus == Node.CONDITION){
            return true;
        }
    }
    return false;
}

/**
 * Returns an estimate of the number of threads waiting on
 * this condition
 * Implements {@link KAbstractOwnableSynchronizer#"getWaitQueueLength()}
 *
 * @return the estimated number of waiting threads
 * @throws IllegalMonitorStateException if {@link #isHeldExclusively()}
 *          return {@code false}
 */
/**
 * 获取 Condition queue 里面的  CONDITION 的节点的个数
 */
protected final int getWaitQueueLength(){
    if(!isHeldExclusively()){
        throw new IllegalMonitorStateException();
    }
    int n = 0;
    for(Node w = firstWaiter; w != null; w = w.nextWaiter){
        if(w.waitStatus == Node.CONDITION){
            ++n;
        }
    }
    return n;
}

/**
 * Returns a collection containing those threads that may be
 * waiting on this Condition
 * Implements {@link KAbstractOwnableSynchronizer#'getWaitingThreads}
 *
 * @return the collection of thread
 * @throws IllegalMonitorStateException if {@link #isHeldExclusively()}
 *          returns {@code false}
 */
/**
 * 获取 等待的线程
 */
protected final Collection<Thread> getWaitingThreads(){
    if(!isHeldExclusively()){
        throw new IllegalMonitorStateException();
    }
    ArrayList<Thread> list = new ArrayList<>();
    for(Node w = firstWaiter; w != null; w = w.nextWaiter){
        if(w.waitStatus == Node.CONDITION){
            Thread t = w.thread;
            if(t != null){
                list.add(t);
            }
        }
    }
    return list;
}

이것에 대한 기사의 끝입니다!

주의를 기울이고 길을 잃지 마십시오! 이 기사가 도움이된다면 좋아요와 지원을 잊지 마세요!

위의 인터뷰 질문에 대한 답변은 문서 노트에 정리되어 있습니다. 인터뷰에 대한 정보와 인터뷰 Zhenti 최신 2020 컬렉션 제조업체 중 일부 (모두 스크린 샷의 작은 부분을 문서화)에 대한 정보를 수집했습니다. 클릭하여 신호를 입력 할 수 있습니다 . CSDN .

모든 분들께 도움이 되었으면 좋겠습니다. 도움이된다면 응원 해주세요!

추천

출처blog.csdn.net/SQY0809/article/details/108579585