java併發源碼:Condition

java併發源碼:Condition

比對Object的監視器方法和Condition接口

對比項 Object Condition
前置條件 獲取對象的鎖 調用Lock.lock()獲取鎖 調用Lock.newCondition()獲取condition對象。
調用方式 直接調用 直接調用
等待隊列個數 1個 多個
當前線程釋放鎖並進入等待狀態 支持 支持
當前線程釋放鎖並進入等待狀態,在等待狀態中不響應中斷 不支持 支持
當前線程釋放鎖並進入超時等待狀態 支持 支持
當前線程釋放鎖並進入等待狀態到將來的某個時間 不支持 支持
喚醒等待隊列中的一個線程 支持 支持
喚醒等待隊列中的全部線程 支持 支持

Condition對象是依賴Lock對象的。

API方法

方法名稱 描述
void await() 當前線程進入等待狀態知道被通知或中斷,當前線程將進入運行狀態且從await()方法返回的情況: 1其它線程中斷當前線程 2如果當前等待線程從await()返回,則表明該線程已經獲取了Condition對象所對應的鎖。
void awaituninterruptibly() 當前線程進入等待狀態直到被通知,從方法名稱上可以看出該方法對中斷不敏感。
long awaitNanos(long nanosTimeout) 當前線程進入等待狀態直到被通知,中斷或者超時。返回值表示剩餘的時間,如果在nanosTimeout納秒之前被喚醒,那麼返回值就是(nanosTimeout-實際耗時)。如果返回值是0或者負數,那麼可以認定已經超時。
boolean awaitUntil(Date deadli) 當前線程進入等待狀態直到被通知,中斷或者直到某個時間,如果沒有到指定時間就被通知,方法返回true,否則到了指定時間,方法返回false
void signal() 喚醒一個等待在Condition的線程,該線程從等待方法返回前必須獲得與Condition相關聯的鎖。
void signalAll() 喚醒所有等待在Condition的線程,能夠從等待方法返回的線程必須獲得與Condition相關聯的鎖。

實現分析

等待隊列:

​ 等待隊列是一個FIFO的隊列,每個節點都包含了一個線程引用,該線程就是在Condition對象等待的線程,如果一個線程調用了Condition.await()方法,那麼該線程將會釋放鎖,構成節點並加入等待隊列並進入等待狀態。

​ 一個對象擁有一個同步隊列和等待隊列。

​ Lock(同步器)擁有一個同步隊列和多個等待隊列。

等待

ConditionObject的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);
}

調用await()方法,相當於從同步隊列的首節點(獲取了鎖的節點)移動到Condition的等待隊列中。

通知

public final void signal() {
    if (!isHeldExclusively())
        throw new IllegalMonitorStateException();
    Node first = firstWaiter;
    if (first != null)
        doSignal(first);
}
private void doSignal(Node first) {
    do {
        if ( (firstWaiter = first.nextWaiter) == null)
            lastWaiter = null;
        first.nextWaiter = null;
    } while (!transferForSignal(first) &&
             (first = firstWaiter) != null);
}
final boolean transferForSignal(Node node) {
    /*
     * If cannot change waitStatus, the node has been cancelled.
     */
    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;
}

​ 當前線程必須是獲取了鎖的線程,接着獲取等待隊列的首節點,將其移動到同步隊列並使用LockSupport喚醒節點中的線程。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章