一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導(dǎo)航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術(shù)|正則表達(dá)式|C/C++|IOS|C#|Swift|Android|VB|R語(yǔ)言|JavaScript|易語(yǔ)言|vb.net|

服務(wù)器之家 - 編程語(yǔ)言 - Java教程 - 類似Object監(jiān)視器方法的Condition接口(詳解)

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

2020-11-02 17:44Java教程網(wǎng) Java教程

下面小編就為大家?guī)?lái)一篇類似Object監(jiān)視器方法的Condition接口(詳解)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧

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

Condition接口的具體實(shí)現(xiàn)還是在AbstractQueuedSynchronizer中的內(nèi)部實(shí)現(xiàn)的——AbstractQueuedSynchronizer$ConditionObject。ConditionObject中維護(hù)了一個(gè)“等待隊(duì)列”,注意這個(gè)和AQS同步器維護(hù)的“同步隊(duì)列”不同。AQS所維護(hù)的同步隊(duì)列是當(dāng)前等待資源(同步狀態(tài))的隊(duì)列,當(dāng)前線程獲取同步狀態(tài)失敗時(shí),同步器會(huì)將當(dāng)前線程以及等待狀態(tài)等信息構(gòu)造成一個(gè)節(jié)點(diǎn)并加入到同步隊(duì)列中,同時(shí)阻塞當(dāng)前線程,當(dāng)同步狀態(tài)被所持有的線程釋放時(shí)會(huì)將同步隊(duì)列中的首節(jié)點(diǎn)喚醒重新獲取同步狀態(tài)。而每個(gè)Condition維護(hù)一個(gè)等待隊(duì)列,該隊(duì)列的作用是一個(gè)等待signal信號(hào)的隊(duì)列。這兩者之間的關(guān)系是一個(gè)協(xié)同的關(guān)系,用下圖的說(shuō)明它們之間的協(xié)同過(guò)程:

1. AQS的同步隊(duì)列如下圖所示,一個(gè)頭結(jié)點(diǎn)head指向隊(duì)首,一個(gè)tail指向隊(duì)尾,當(dāng)線程調(diào)用lock()方法獲取鎖而未成功時(shí),線程被構(gòu)造成節(jié)點(diǎn)加入到隊(duì)尾。(圖中NodeA是同步隊(duì)列的第一個(gè)節(jié)點(diǎn),也就是獲得同步狀態(tài)的節(jié)點(diǎn))

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

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

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

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

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

4. 最后NodeB在signal執(zhí)行完畢后,調(diào)用unLock方法釋放鎖,此時(shí)NodeA處于隊(duì)首,并爭(zhēng)奪同步狀態(tài)。

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public final void await() throws InterruptedException{
 if (Thread.interrupted()) //線程被中斷則拋出中斷異常
 throw new InterruptedException();
 Node node = addConditionWaiter(); //將線程構(gòu)造為Node節(jié)點(diǎn)
 long savedState = fullyRelease(node); //釋放鎖,返回同步狀態(tài)
 int interruptMode = 0;
 while (!isOnSyncQueue(node)) { //循環(huán)判斷當(dāng)前節(jié)點(diǎn)是否在同步隊(duì)列中
 LockSupport.park(this);
 if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
  break; //檢查節(jié)點(diǎn)在處于等待狀態(tài)時(shí)是否被中斷
  }
  //在跳出了循環(huán),即被signal喚醒后重新加入了同步隊(duì)列后,開始重新競(jìng)爭(zhēng)鎖
  if (acquireQueued(node, savedState) && interruptMode != THROW_IE) //acquireQueued自旋獲取鎖,具體分析見《2.從AbstractQueuedSynchronizer(AQS)說(shuō)起(1)——獨(dú)占模式的鎖獲取與釋放》中對(duì)獲取同步狀態(tài)的解析
    interruptMode = REINTERRUPT;
  if (node.nextWaiter != null)
   unlinkCancelledWaiters(); //如果節(jié)點(diǎn)從等待狀態(tài)轉(zhuǎn)換為在同步隊(duì)列中,并且也已經(jīng)獲得了鎖,此時(shí)將斷開此節(jié)點(diǎn)后面的等待節(jié)點(diǎn)
  if (interruptMode != 0)
   reportInterruptAfterWait(interruptMode);
 }

在獲取鎖的線程調(diào)用await時(shí),首先會(huì)將線程構(gòu)造為Node節(jié)點(diǎn)并釋放鎖,此時(shí)線程被移出同步隊(duì)列加入到Condition等待隊(duì)列中,接著在第7行就會(huì)while循環(huán)判斷節(jié)點(diǎn)是否在同步隊(duì)列中,當(dāng)沒有線程調(diào)用signal方法的時(shí)候顯然線程不在同步隊(duì)列,并將一直循環(huán),直到有線程調(diào)用signal方法該線程才會(huì)被喚醒加入到同步隊(duì)列中,此時(shí)才會(huì)跳出循環(huán)。

signal和signalAll方法的異同在和notify和notifyAll一樣。signal只會(huì)喚醒等待隊(duì)列中位于隊(duì)首的節(jié)點(diǎn)使其具有競(jìng)爭(zhēng)鎖的資格,而signalAll則會(huì)喚醒等待隊(duì)列中所有節(jié)點(diǎn)使所有節(jié)點(diǎn)都具有競(jìng)爭(zhēng)鎖的資格。

?
1
2
3
4
5
6
7
public final void signal() {
 if (!isHeldExclusively()) //判斷當(dāng)前線程是否持有鎖
 throw new IllegalMonitorStateException();
 Node first = firstWaiter;
 if (first != null)
 doSignal(first); //喚醒等待隊(duì)列中的第一個(gè)節(jié)點(diǎn)
}

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

?
1
2
3
4
5
6
7
private void doSignal(Node first) {
 do {
 if ((firstWaiter = first.nextWaiter) == null)
  lastWaiter = null;
 first.nextWaiter = null;
} while (!transferForSignal(first) && (first = firstWaiter) != null) //transferForSignal方法將處于等待隊(duì)列中的節(jié)點(diǎn)添加到同步隊(duì)列中
}

至于doSignalAll則是循環(huán)調(diào)用transferForSignal使得所有節(jié)點(diǎn)都被喚醒加入到同步隊(duì)列中。

當(dāng)節(jié)點(diǎn)從等待隊(duì)列中加入到同步隊(duì)列中時(shí),呼應(yīng)await中的循環(huán)等待節(jié)點(diǎn)是否在同步隊(duì)列中,await和signal的協(xié)同配合也就很清晰明了了。

以上這篇類似Object監(jiān)視器方法的Condition接口(詳解)就是小編分享給大家的全部?jī)?nèi)容了,希望能給大家一個(gè)參考,也希望大家多多支持服務(wù)器之家。

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 国产一区二区三区高清 | 男人狂躁女人下面狂叫图片 | 国产精品视频播放 | 三年片韩国在线 | 免费免费啪视频在线观播放 | 亚洲精品视频观看 | 性生大片免费看 | 51国产午夜精品免费视频 | 嫩草影院永久在线播放 | 日韩欧美一区二区三区视频 | youjizzxxx69日本 | 亚洲乱码一二三四五六区 | 本土自拍 | 513热点| 国产精品久久久久久久福利院 | 国产一级毛片潘金莲的奶头 | 大肥臀风间由美 中文字幕 大东北chinesexxxx露脸 | 欠操h | 免费看1级伦理 | h视频免费高清在线观看 | 欧美cosplay极品video | 嗯啊视频在线观看 | 精品国产一区二区在线观看 | 日韩一区二区三区不卡视频 | 色悠久久久久综合网小说 | 国产精品青青青高清在线观看 | 爆操美女在线观看 | 日本三级大学生17 | 美女扒开胸罩露出奶了无遮挡免费 | 亚洲 欧美 偷自乱 图片 | 无码一区二区三区视频 | 成年私人影院免费视频网站 | 男男gaygays中国 | 国产精品久久久久一区二区三区 | 2018天天拍拍拍免费视频 | 亚洲a在线视频 | 97伊人久久精品亚洲午夜 | 久见久热 这里只有精品 | 国产免费视频 | 日韩综合网 | 第一福利在线观看永久视频 |