91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

類似Object監視器方法的Condition接口(詳解)

發布時間:2020-10-09 16:06:06 來源:腳本之家 閱讀:180 作者:jingxian 欄目:編程語言

在《基于線程、并發的基本概念(詳解)》中,我們利用synchronized關鍵字、Queue隊列、以及Object監視器方法實現了生產者消費者,介紹了有關線程的一些基本概念。Object類提供的wait的方法和notifyAll方法,與之對應的是Condition接口提供是await和signalAll。await(或wait)是讓當前線程進入等待狀態并釋放鎖,signalAll(或notifyAll)則是喚醒等待中的線程,使得等待中的線程有競爭鎖的資格,注意只是資格,并不代表被喚醒的線程就一定會獲得鎖。

Condition接口的具體實現還是在AbstractQueuedSynchronizer中的內部實現的——AbstractQueuedSynchronizer$ConditionObject。ConditionObject中維護了一個“等待隊列”,注意這個和AQS同步器維護的“同步隊列”不同。AQS所維護的同步隊列是當前等待資源(同步狀態)的隊列,當前線程獲取同步狀態失敗時,同步器會將當前線程以及等待狀態等信息構造成一個節點并加入到同步隊列中,同時阻塞當前線程,當同步狀態被所持有的線程釋放時會將同步隊列中的首節點喚醒重新獲取同步狀態。而每個Condition維護一個等待隊列,該隊列的作用是一個等待signal信號的隊列。這兩者之間的關系是一個協同的關系,用下圖的說明它們之間的協同過程:

1. AQS的同步隊列如下圖所示,一個頭結點head指向隊首,一個tail指向隊尾,當線程調用lock()方法獲取鎖而未成功時,線程被構造成節點加入到隊尾。(圖中NodeA是同步隊列的第一個節點,也就是獲得同步狀態的節點)

類似Object監視器方法的Condition接口(詳解)

2.NodeA調用await()方法時,NodeA從AQS同步隊列中移除,自然也就釋放了鎖,NodeA此時被加入到Condition的等待隊列中,等待signal信號,如下圖所示。

  類似Object監視器方法的Condition接口(詳解)

3.執行完第2步后,此時NodeB在同步隊列中處于第一個節點位置,即獲取到了鎖,如果NodeB此時執行signal(或者signalAll)方法,NodeA將會從Condition等待隊列中被移除即被喚醒,加入到同步隊列中,此時NodeA僅僅是被喚醒有了在同步隊列中爭奪資源的資格,并不代表被喚醒后就立即獲得鎖,如下圖所示。

類似Object監視器方法的Condition接口(詳解)

4. 最后NodeB在signal執行完畢后,調用unLock方法釋放鎖,此時NodeA處于隊首,并爭奪同步狀態。

以上是AQS的“同步隊列”和Condition的“等待隊列”之間相互協作的過程,下面從源碼解析Condition的主要方法await、signal、signalAll。

public final void await() throws InterruptedException{
 if (Thread.interrupted()) //線程被中斷則拋出中斷異常
 throw new InterruptedException();
 Node node = addConditionWaiter(); //將線程構造為Node節點
 long savedState = fullyRelease(node); //釋放鎖,返回同步狀態
 int interruptMode = 0;
 while (!isOnSyncQueue(node)) { //循環判斷當前節點是否在同步隊列中
 LockSupport.park(this);
 if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
  break; //檢查節點在處于等待狀態時是否被中斷
  }
  //在跳出了循環,即被signal喚醒后重新加入了同步隊列后,開始重新競爭鎖
  if (acquireQueued(node, savedState) && interruptMode != THROW_IE) //acquireQueued自旋獲取鎖,具體分析見《2.從AbstractQueuedSynchronizer(AQS)說起(1)——獨占模式的鎖獲取與釋放》中對獲取同步狀態的解析
    interruptMode = REINTERRUPT; 
  if (node.nextWaiter != null) 
   unlinkCancelledWaiters(); //如果節點從等待狀態轉換為在同步隊列中,并且也已經獲得了鎖,此時將斷開此節點后面的等待節點
  if (interruptMode != 0)
   reportInterruptAfterWait(interruptMode);
 }

在獲取鎖的線程調用await時,首先會將線程構造為Node節點并釋放鎖,此時線程被移出同步隊列加入到Condition等待隊列中,接著在第7行就會while循環判斷節點是否在同步隊列中,當沒有線程調用signal方法的時候顯然線程不在同步隊列,并將一直循環,直到有線程調用signal方法該線程才會被喚醒加入到同步隊列中,此時才會跳出循環。

signal和signalAll方法的異同在和notify和notifyAll一樣。signal只會喚醒等待隊列中位于隊首的節點使其具有競爭鎖的資格,而signalAll則會喚醒等待隊列中所有節點使所有節點都具有競爭鎖的資格。

public final void signal() {
 if (!isHeldExclusively()) //判斷當前線程是否持有鎖
 throw new IllegalMonitorStateException();
 Node first = firstWaiter;
 if (first != null)
 doSignal(first); //喚醒等待隊列中的第一個節點
}

對比signalAll方法,不同點在于第6行是喚醒等待隊列中的所有節點——doSignalAll(first),不再貼出代碼。

private void doSignal(Node first) {
 do {
 if ((firstWaiter = first.nextWaiter) == null)
  lastWaiter = null;
 first.nextWaiter = null;
} while (!transferForSignal(first) && (first = firstWaiter) != null) //transferForSignal方法將處于等待隊列中的節點添加到同步隊列中
}

至于doSignalAll則是循環調用transferForSignal使得所有節點都被喚醒加入到同步隊列中。

當節點從等待隊列中加入到同步隊列中時,呼應await中的循環等待節點是否在同步隊列中,await和signal的協同配合也就很清晰明了了。

以上這篇類似Object監視器方法的Condition接口(詳解)就是小編分享給大家的全部內容了,希望能給大家一個參考,也希望大家多多支持億速云。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

揭阳市| 锦州市| 丹阳市| 长沙县| 溧水县| 保定市| 安仁县| 依兰县| 县级市| 九龙县| 辉南县| 金川县| 房山区| 襄城县| 江津市| 根河市| 望城县| 陆川县| 丘北县| 麻栗坡县| 金坛市| 武穴市| 成都市| 黄陵县| 泽库县| 惠水县| 防城港市| 札达县| 茶陵县| 济南市| 唐山市| 万州区| 奉新县| 盐城市| 盐源县| 湖州市| 房产| 随州市| 元氏县| 饶平县| 昌吉市|