AQS的Condition源碼解析

1. Condition 譜系圖

在這裏插入圖片描述

2. Condition 接口

  • await
    當前線程在接到信號或被中斷前處於等待狀態
  • await(long time,TimeUnit unit)
    當前線程在接到信號、被中斷或者到達指定等待時間之前一直處於等待狀態
  • awaitNanos(long nanosTimeout)
    當前線程在接到信號、被中斷或者到達指定等待時間之前一直處於等待狀態
  • awaitUninterruptibly()
    當前線程在接到信號之前一直處於等待狀態
  • awaitUntil(Date deadline)
    當前線程在接到信號、被中斷或到達指定最後期限之前一直處於等待狀態
  • signal()
    喚醒一個等待線程
  • signalAll()
    喚醒所有等待線程

3. AQS 中實現的Condition接口

3.1 ConditionObject 存儲結構

在這裏插入圖片描述
在ConditionObject中,保存了條件隊列的第一個等待節點,以及條件隊列的最後一個等待節點。

請注意,在AQS中,有兩個雙向隊列,在AQS外部有一個,分別用head和tail進行引用雙向列表的頭結點和尾節點;在ConditionObject中也有一個雙向列表,用firstWaiter和lastWaiter進行引用雙向列表的頭節點和尾節點。

3.2 addConditionWaiter

// 新增當前線程節點到雙向列表中
private Node addConditionWaiter() {
    Node t = lastWaiter; // 獲取雙向列表的尾節點
    // If lastWaiter is cancelled, clean out.
    // 如果雙向列表的尾節點不是CONDITION節點,那麼調用unlinkCancelledWaiters方法清理雙向列表
    if (t != null && t.waitStatus != Node.CONDITION) {
        unlinkCancelledWaiters();
        // 在unlinkCancelledWaiters方法中已經更新了尾節點
        t = lastWaiter;
    }
    // 根據當前線程創建當前線程的CONDITION的線程節點
    Node node = new Node(Thread.currentThread(), Node.CONDITION);
    // 如果t爲空,表示尾節點爲空,也就是說,雙向列表中現在是空的
    if (t == null)
    	// 將當前新增的線程節點設置爲雙向列表的頭節點
        firstWaiter = node;
    else
    	// 否則將新增的線程節點連接到雙向列表的尾節點上
        t.nextWaiter = node;
    // 更新尾節點
    // 如果雙向列表中只有一個線程節點,此時頭結點和尾節點相同
    // 如果雙向列表中一個線程節點都沒有,那麼此時尾節點爲空,頭節點初始化的是空節點
    lastWaiter = node;
    return node;
}
// 清理雙向列表中不是CONDITION的節點
private void unlinkCancelledWaiters() {
	// 得到雙向列表的頭,作爲循環的第一個節點
    Node t = firstWaiter;
    // 定義當前循環節點的前繼節點
    Node trail = null;
    // 循環節點不爲空,那麼就一直循環
    while (t != null) {
    	// 獲取循環節點的後繼節點
        Node next = t.nextWaiter;
        // 如果當前循環節點的等待狀態不是CONDITION
        if (t.waitStatus != Node.CONDITION) {
        	// 設置當前循環的後繼節點爲空 
        	// 當前循環節點與雙向列表做後繼斷裂
            t.nextWaiter = null;
            // 如果當前循環節點的前繼爲空,表示當前節點是頭結點(頭結點沒有前繼節點)
            if (trail == null)
            	// 頭結點設置爲當前循環節點的後繼節點
                firstWaiter = next;
            else
            // 如果當前循環節點的前繼不爲空,那麼設置當前循環節點的前繼節點的後繼節點爲當前循環節點的後繼節點
            // a -> b -> c => a -> c
                trail.nextWaiter = next;
            // 如果當前循環節點的後繼節點的後繼爲空,那麼表示當前循環節點是尾節點(尾節點沒有後繼節點)
            // 類似於 a -> b -> c : t<=> c
            if (next == null)
            	// 如果尾節點不存在表示當前節點已經是尾節點,那麼將當前循環節點的前繼節點設置爲尾節點
            	// 類似於 a-> b -> c: t <=> c;trail <=> b
                lastWaiter = trail;
        }
        // 如果當前循環節點是CONDITION節點,那麼設置循環節點的前繼節點爲當前循環節點(準備下一次循環)
        else
            trail = t;
        // 偏移當前循環節點
        t = next;
    }
}

3.3 doSignal

// 執行通知操作,通知等待通知的線程節點。將CONDITION節點轉換爲SIGNAL節點
private void doSignal(Node first) {
    do {
    	// 因爲頭節點是一個空節點,所以在通知的時候需要跳過頭結點
        if ( (firstWaiter = first.nextWaiter) == null)
        	// 如果頭結點的後繼節點爲空,那麼表示雙向列表爲空
        	// 設置尾節點爲空
            lastWaiter = null;
        // 如果first的後繼節點不爲空,那麼將first的後繼節點設置爲空
        first.nextWaiter = null;
    } while (!transferForSignal(first) &&
             (first = firstWaiter) != null);
}
// 將CONDITION節點轉爲SIGNAL節點
final boolean transferForSignal(Node node) {
    /*
     * If cannot change waitStatus, the node has been cancelled.
     */
    // 將CONDITION節點的等待狀態設置爲初始化狀態0,如果設置失敗,那麼說明當前節點不是CONDITION節點了
    // 那麼就跳過這個節點,結束,進行doSignal的下一次循環
    // 如果設置成功,那麼,這個節點需要從等待通知狀態轉移到等待競爭鎖的雙向列表中了,那麼就繼續執行下面的代碼
    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加到雙向列表的尾節點處
   	// 請注意,在AQS中有兩個雙向列表:AQS等待競爭鎖雙向列表;ConditionObject等待通知雙向隊列
   	// 這裏將節點node從等待通知雙向隊列轉移到了等待競爭鎖雙向列表
   	// 等待通知雙向列表中的節點的等待狀態都是CONDITION狀態
    Node p = enq(node);
    // 獲取node的等待狀態
    int ws = p.waitStatus;
    // 如果node的狀態是取消狀態或者設置線程節點的等待狀態爲SIGNAL失敗
    if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL))
    	// 喚醒線程
        LockSupport.unpark(node.thread);
	// 結束循環
    return true;
}

3.4 doSignalAll

private void doSignalAll(Node first) {
	// 因爲需要將等待通知列表中的節點全部轉換,所以直接清空等待通知列表的頭結點和尾節點
    lastWaiter = firstWaiter = null;
    do {
    	// 等待通知雙向列表的頭結點已經保存在了first中了
    	// 獲得雙向列表中頭結點的後繼節點
        Node next = first.nextWaiter;
        // 將當前循環節點的後繼節點設置爲空,後繼斷裂
        first.nextWaiter = null;
        // 將當前CONDITION節點轉換爲SIGNAL節點
        transferForSignal(first);
        // 偏移當前節點爲後繼節點
        first = next;
    } while (first != null);// 循環節點不爲空
}

3.5 unlinkCancelledWaiters

private void unlinkCancelledWaiters() {
	// 獲取等待通知雙向列表的頭結點
    Node t = firstWaiter;
    // 定義循環節點的前繼節點
    Node trail = null;
    while (t != null) { // 循環節點不爲空
        // 獲取循環節點的後繼節點
        Node next = t.nextWaiter;
        // 循環節點不是CONDITION節點
        if (t.waitStatus != Node.CONDITION) {
        	// 循環節點的後繼節點設置爲空
            t.nextWaiter = null;
            // 如果循環節點的前繼節點爲空,那麼說明循環節點就是頭節點
            if (trail == null)
            	// 設置頭節點爲循環節點的後繼節點
                firstWaiter = next;
            else
            	// 如果循環節點的前繼節點不爲空,那麼說明循環節點是中間節點
            	// 設置循環節點的前繼節點的後繼是循環節點的後繼節點
            	// 簡單來說就是跳過循環節點,將循環節點前面和後面連接起來
                trail.nextWaiter = next;
            // 如果循環節點的後繼節點爲空,表示循環節點就是尾節點
            if (next == null)
            	// 設置尾節點是循環節點的前繼節點(跳過循環節點)
                lastWaiter = trail;
        }
        else
        	// 循環節點是CONDITION節點
        	// 偏移循環節點的前繼節點是循環節點
            trail = t;
        // 偏移循環節點是循環節點的後繼節點
        t = next;
    }
}

3.6 signal

public final void signal() {
	// 是否是獨佔模式,只有condition纔會用到
    if (!isHeldExclusively())
    	// 如果不是獨佔模式,那麼拋出異常
        throw new IllegalMonitorStateException();
    // 獲得等待通知雙向列表的頭節點
    Node first = firstWaiter;
    // 如果頭節點不爲空,那麼通知頭結點
    if (first != null)
        doSignal(first);
}

這也是爲什麼在doSignal中頭節點需要向後偏移一次。
因爲這個方法只會處理第一個節點

3.7 signalAll

public final void signalAll() {
	// 是否是獨佔模式
    if (!isHeldExclusively())
        throw new IllegalMonitorStateException();
    // 獲取等待通知雙向列表
    Node first = firstWaiter;
    // 頭結點不爲空,意味着等待通知雙向列表不爲空
    if (first != null)
    	// 從第一個節點開始,通知全部節點
        doSignalAll(first);
}

因爲通知了全部節點,所以頭結點和尾節點就沒有必要再引用舊的不屬於等待通知的節點了,所以在doSignalAll中清空了頭結點和尾節點

3.8 awaitUninterruptibly

這個方法的作用是阻塞等待通知,阻塞期間不響應中斷
其時序圖如下:
在這裏插入圖片描述
這個方法看上去很複雜,不過不要怕,我們一步一步看

// 等待通知,不響應中斷
public final void awaitUninterruptibly() {
	// 將當前線程添加到等待通知雙向隊列中
    Node node = addConditionWaiter();
    // 調用fullyRelease方法,傳入的是等待通知隊列中的尾節點
    int savedState = fullyRelease(node); // 這裏得到的等待狀態是 -2
    boolean interrupted = false;
    // 如果不是等待競爭隊列節點,那麼一直循環,直到找到等待競爭隊列的節點
    while (!isOnSyncQueue(node)) { 
        LockSupport.park(this); // 如果等待競爭隊列中不存在等待競爭節點,那麼阻塞當前線程,進入自旋
        if (Thread.interrupted()) // 獲取線程的中斷標誌,並重置中斷標誌,這裏是不響應中斷,只是記錄了中斷狀態
            interrupted = true;
    }
    // 如果等待競爭隊列中存在等待競爭節點,那麼就自旋獲取鎖
    if (acquireQueued(node, savedState) || interrupted) // 如果自旋獲取鎖失敗或者線程被中斷,那麼就中斷線程
        selfInterrupt();
}
final int fullyRelease(Node node) {
	// 完全嘗試釋放鎖
    boolean failed = true;
    try {
    	// 獲取線程節點的等待狀態(這個節點是傳入的等待通知隊列的尾節點)
        int savedState = getState();
        // 調用獨佔鎖實現的釋放鎖的方法,如果釋放失敗會拋出異常
        // 如果調用定義的tryRelease嘗試釋放鎖成功,那麼就會獲取等待競爭隊列的頭結點
        // 然後喚醒等待競爭隊列的第二個節點(等待競爭鎖隊列的頭結點是空節點)
        if (release(savedState)) { // 此時savedState 的值是 -2
        	// 等待通知隊列的尾節點釋放鎖成功
            // 是否取消等待通知隊列的尾節點
            failed = false;
            // 返回等待通知
            return savedState;
        } else {
            throw new IllegalMonitorStateException();
        }
    } finally {
        if (failed)
            node.waitStatus = Node.CANCELLED;
    }
}
// 釋放鎖
public final boolean release(int arg) {
	// 嘗試釋放鎖 ,此時arg = -2
    if (tryRelease(arg)) {
        Node h = head; // 獲取等待競爭線程節點隊列
        if (h != null && h.waitStatus != 0)
            unparkSuccessor(h); // 喚醒隊列最前面的線程節點的線程
        return true;
    }
    return false;
}
//喚醒線程,請注意,這裏真正喚醒的是傳入節點的後繼節點
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); // 喚醒線程
}
// 是否是等待競爭隊列的節點
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;
    /*
     * 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);
}
// 從爲節點開始,遍歷等待通知隊列,查找等待通知隊列中是否存在傳入的節點
private boolean findNodeFromTail(Node node) {
    Node t = tail;
    for (;;) {
        if (t == node)
            return true;
        if (t == null)
            return false;
        t = t.prev;
    }
}
// 自旋獲取鎖
final boolean acquireQueued(final Node node, int arg) { // 這裏傳入的節點是等待通知隊列的節點,arg = -2
    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.9 await

這是await的時序圖
在這裏插入圖片描述
這些方法基本邏輯都差別不大,詳細閱讀了一個方法源碼,根據源碼一步一步往下看,除了一些細節,大致上差不多。

// 等待通知,響應中斷
public final void await() throws InterruptedException {
	// 獲取線程的中斷標誌,並重置中斷標誌
    if (Thread.interrupted())
    	// 如果線程已經中斷,那麼直接拋出中斷異常快速失敗
        throw new InterruptedException();
    // 將當前節點加入等待通知隊列
    Node node = addConditionWaiter();
    // 嘗試獲取鎖
    int savedState = fullyRelease(node);
    int interruptMode = 0;
    // 是否是等待競爭隊列節點,這裏其實是自旋,如果等待通知隊列節點一直沒有收到通知,那麼這個循環一直成立,一直在自旋等待線程節點從等待通知隊列轉移到等待競爭隊列
    while (!isOnSyncQueue(node)) {
        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);
}
// 檢測中斷狀態
private int checkInterruptWhileWaiting(Node node) {
    return Thread.interrupted() ? // 獲取線程的中斷標誌,且重置
        (transferAfterCancelledWait(node) ? THROW_IE : REINTERRUPT) : // 返回true表示這個節點是由當前線程進行的轉移,否則就
        // 是其他線程進行的轉移,那麼哪個線程負責的轉移,就由哪個線程負責拋出中斷異常
        // 其他線程只是獲取下狀態
        0; // 未中斷,直接返回0
}
final boolean transferAfterCancelledWait(Node node) {
	// cas將等待通知節點的等待狀態設置爲0,表示已經得到通知,可以將等待通知線程節點轉移到等待競爭隊列
    if (compareAndSetWaitStatus(node, Node.CONDITION, 0)) { // 這一步是爲了將node設置爲新建的等待競爭隊列節點,這個0表示這個節點可以當做等待競爭隊列的新建節點
    	// 將node加入到等待競爭隊列中
        enq(node);
        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.
     */
     // 表示node的等待狀態已經被修改,那麼就自旋等待轉移完成,此時可以理解爲其他線程正在轉移,但是還未轉移完成
    while (!isOnSyncQueue(node))
        Thread.yield(); // 如果在等待競爭隊列中沒有找到這個節點,那麼就自旋等待轉移完成
    return false;
}
// 中斷處理模式,到底是直接拋出異常還是直接線程中斷(這裏需要注意,拋出異常,但是線程並未中斷)
// 爲什麼這麼做?當前線程處理的節點和其他線程處理的節點可能是同一個節點,那麼,在其他線程中已經進行中斷
// 那麼當前線程就是對中斷線程進行中斷,所以拋出中斷異常
private void reportInterruptAfterWait(int interruptMode)
    throws InterruptedException {
    if (interruptMode == THROW_IE)
        throw new InterruptedException();
    else if (interruptMode == REINTERRUPT)
        selfInterrupt();
}

3.10 awaitNanos

這是awaitNanos的時序圖:
在這裏插入圖片描述
這個等待一定的時間的方法和前面的等待大同小異吧

// 等待指定的時間,如果時間到了,還未收到通知,那麼就拋出結束等待,同時在等待的期間,響應中斷異常
public final long awaitNanos(long nanosTimeout)
        throws InterruptedException {
    // 首先檢測線程中斷,且重置
    if (Thread.interrupted())
        throw new InterruptedException(); // 如果線程已經被中斷,直接拋出中斷異常
    Node node = addConditionWaiter(); // 將當前線程加入到等待通知隊列尾
    // 嘗試釋放鎖
    int savedState = fullyRelease(node); // 此時獲取的狀態是-2
    final long deadline = System.nanoTime() + nanosTimeout; // 獲取當前時間,當前時間加上等待時間,就是截止時間
    int interruptMode = 0; // 中斷模式
    while (!isOnSyncQueue(node)) { // 自旋等待線程節點從等待通知隊列轉移到等待競爭隊列
        if (nanosTimeout <= 0L) { // 如果等待時間小於等於0,那麼就取消當前節點
            transferAfterCancelledWait(node);
            break; // 結束自旋
        }
        // 如果剩餘等待時間大於100納秒,那麼就進行線程阻塞,否則進行自旋等待時間結束
        if (nanosTimeout >= spinForTimeoutThreshold)
        	// 阻塞當前線程指定時間
            LockSupport.parkNanos(this, nanosTimeout);
        // 檢查等待時間內的中斷標誌,並重置
        if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
        	// 如果已經被中斷,那麼結束自旋
            break;
        // 更新剩餘等待時間
        nanosTimeout = deadline - System.nanoTime();
    }
    // 此時node節點已經從等待通知隊列轉移到了等待競爭隊列,或者剩餘等待時間爲0
    if (acquireQueued(node, savedState) && interruptMode != THROW_IE) // 如果不是當前線程處理node,那麼獲取中斷標誌且重置
        interruptMode = REINTERRUPT;
    if (node.nextWaiter != null) // 後繼節點不爲空,表示node後面還有節點
        unlinkCancelledWaiters(); // 清理等待通知隊列中等待狀態不是CONDITION的節點
    if (interruptMode != 0) // 如果中斷模式不是0,表示線程已經被中斷,那麼需要根據中斷模式判斷是不是當前線程處理的中斷
        reportInterruptAfterWait(interruptMode); // 如果是當前線程在自旋期間被中斷,那麼拋出中斷異常,否則將當前線程進行中斷
    return deadline - System.nanoTime(); // 成功獲取鎖,那麼就返回剩餘時間
}
final boolean transferAfterCancelledWait(Node node) {
	// cas 將當前線程節點的等待狀態設置爲0,然後加入到等待競爭狀態
    if (compareAndSetWaitStatus(node, Node.CONDITION, 0)) {
        enq(node);
        return true; // 表示node節點是由當前線程進行轉移的
    }
    /*
     * 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.
     */
    // 如果當前節點不在等待競爭隊列,那麼自旋等待轉移完成
    while (!isOnSyncQueue(node))
        Thread.yield(); // 讓出cpu時間,給其他線程處理
    return false; // 表示node是由其他線程進行轉移的
}
// 清理等待通知隊列中等待狀態不是CONDITION的節點
private void unlinkCancelledWaiters() {
    Node t = firstWaiter; // 獲取等待通知隊列的隊列頭
    Node trail = null; // 設置臨時變量存儲循環節點的前繼
    while (t != null) { // 如果等待通知隊列的隊列頭不是空,表示等待通知隊列不空
        Node next = t.nextWaiter; // 獲取等待通知的隊列頭的後繼
        if (t.waitStatus != Node.CONDITION) { // 如果等待通知隊列的隊列頭的等待狀態不是 -2
            t.nextWaiter = null; // 那麼就需要將隊列頭從等待通知隊列中移除,這裏是斷開隊列頭的後繼鏈接
            if (trail == null) // 如果當前循環節點的前繼是空,那麼設置隊列頭是當前循環節點的後繼,即隊列頭向後偏移
                firstWaiter = next;
            else
                trail.nextWaiter = next; // 否則設置當前循環節點的前繼節點與當前循環節點的後繼節點相連,即移除當前循環節點
            if (next == null) // 如果後繼爲空,那麼就設置隊列尾是當前循環節點的前繼,即隊列尾前移
                lastWaiter = trail;
        }
        else // 如果當前循環節點的狀態是 -2 ,那麼偏移當前循環節點的前繼
            trail = t;
        // 偏移當前循環節點是後繼,進行下一次循環
        t = next;
    }
}

3.11 awaitUntil

這個方法和3.10的方法區別在於:3.10等待時間較短,等待時間的單位是納秒,這個等待的時間的單位是日期,範圍上比3.10要大
這是awaitUntil的時序圖
在這裏插入圖片描述

public final boolean awaitUntil(Date deadline)
        throws InterruptedException {
    long abstime = deadline.getTime();
    if (Thread.interrupted())
        throw new InterruptedException();
    Node node = addConditionWaiter();
    int savedState = fullyRelease(node);
    boolean timedout = false;
    int interruptMode = 0;
    while (!isOnSyncQueue(node)) { // 自旋等待node接收到通知,然後從等待通知隊列轉移到等待競爭隊列
        if (System.currentTimeMillis() > abstime) { // 這裏處理的時間單位是毫秒
            timedout = transferAfterCancelledWait(node);
            break;
        }
        LockSupport.parkUntil(this, abstime);
        if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
            break;
    }
    if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
        interruptMode = REINTERRUPT;
    if (node.nextWaiter != null)
        unlinkCancelledWaiters();
    if (interruptMode != 0)
        reportInterruptAfterWait(interruptMode);
    return !timedout;
}

3.12 await(long time, TimeUnit unit)

這個比3.11更加靈活,由調用者傳入時間和時間單位
這是時序圖
在這裏插入圖片描述

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) // 如果大於1000納秒進行阻塞
            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;
}

3.13 getWaitQueueLength

獲取等待通知隊列中節點的數量
這是時序圖
在這裏插入圖片描述

protected final int getWaitQueueLength() {
    if (!isHeldExclusively()) // 獲取當前線程是否是獨佔的,這個方法只有在ConditionObject中會調用
        throw new IllegalMonitorStateException();
    int n = 0;
    for (Node w = firstWaiter; w != null; w = w.nextWaiter) {
        if (w.waitStatus == Node.CONDITION)
            ++n;
    }
    return n; // 返回等待通知隊列中CONDITION的節點數量
}
// 在AQS中對內部類的方法做了代理
public final int getWaitQueueLength(ConditionObject condition) {
    if (!owns(condition))
        throw new IllegalArgumentException("Not owner");
    return condition.getWaitQueueLength();
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章