摘要:關(guān)于接口的介紹,可以參見多線程進(jìn)階二鎖框架接口。最終線程釋放了鎖,并進(jìn)入阻塞狀態(tài)。當(dāng)線程被通知喚醒時(shí),則是將條件隊(duì)列中的結(jié)點(diǎn)轉(zhuǎn)換成等待隊(duì)列中的結(jié)點(diǎn),之后的處理就和獨(dú)占功能完全一樣。
本文首發(fā)于一世流云的專欄:https://segmentfault.com/blog...一、本章概述
本章將繼續(xù)以ReentrantLock的調(diào)用為例,說明AbstractQueuedSynchronizer提供的Conditon等待功能。關(guān)于Conditon接口的介紹,可以參見:Java多線程進(jìn)階(二)—— juc-locks鎖框架:接口。
二、Condition接口的實(shí)現(xiàn)J.U.C包提供了Conditon接口,用以對(duì)原生的Object.wait()、Object.notify()進(jìn)行增強(qiáng)。
Condition接口的實(shí)現(xiàn)類其實(shí)是在AQS中——ConditionObject,ReentranLock的newConditon方法其實(shí)是創(chuàng)建了一個(gè)AbstractQueuedSynchronizer.ConditionObject對(duì)象:
Condition作為AQS的內(nèi)部類,復(fù)用了AQS的結(jié)點(diǎn),維護(hù)一個(gè)條件隊(duì)列,隊(duì)列初始時(shí)的結(jié)構(gòu)如下:
假設(shè)現(xiàn)在有3個(gè)線程:ThreadA、ThreadB、ThreadC,一個(gè)Conditon實(shí)現(xiàn)對(duì)象。
ReentrantLock lock = new ReentrantLock();
Conditon con = lock.newConditon();
線程將以以下的時(shí)序調(diào)用:
//ThreadA先調(diào)用lock方法獲取到鎖,然后調(diào)用con.await() //ThreadB獲取鎖,調(diào)用con.signal()喚醒ThreadA //ThreadB釋放鎖1. ThreadA獲取到鎖后,首先調(diào)用await方法
上述方法,先對(duì)線程中斷做一次預(yù)判斷,然后將線程包裝成結(jié)點(diǎn)插入【條件隊(duì)列】,插入完成后,條件隊(duì)列的結(jié)構(gòu)如下:
我們知道,await()方法會(huì)釋放當(dāng)前線程持有的鎖,這個(gè)過程其實(shí)就是fullyRelease方法的作用:
然后,判斷當(dāng)前結(jié)點(diǎn)是不是在【等待隊(duì)列】中,不在的話就會(huì)阻塞線程。
最終線程A釋放了鎖,并進(jìn)入阻塞狀態(tài)。
由于Condition的signal方法要求線程必須獲得與此Condition對(duì)象相關(guān)聯(lián)的鎖,所以這里有個(gè)中斷判斷:
然后,會(huì)調(diào)用doSignal方法,刪除條件隊(duì)列中的隊(duì)首CONDITION類型結(jié)點(diǎn):
刪除完成后,transferForSignal方法會(huì)將CONDITON結(jié)點(diǎn)轉(zhuǎn)換為初始結(jié)點(diǎn),并插入【等待隊(duì)列】:
此時(shí),【條件隊(duì)列】已經(jīng)空了:
而ThreadA被包裝成新結(jié)點(diǎn)后,插入【等待隊(duì)列】:
終于ThreadB釋放了鎖,釋放成功后,會(huì)調(diào)用unparkSuccessor方法(參加AQS獨(dú)占功能的講解),喚醒隊(duì)列中的首結(jié)點(diǎn):
最終等待隊(duì)列結(jié)構(gòu)如下:
ThreadA被喚醒后,從await方法的阻塞處開始繼續(xù)往下執(zhí)行:
之后會(huì)調(diào)用acquireQueued方法再次嘗試獲取鎖,獲取成功后,最終等待隊(duì)列狀態(tài)如下:
三、總結(jié)本章以ReentrantLock的公平鎖為例,分析了AbstractQueuedSynchronizer的Condition功能。
通過分析,可以看到,當(dāng)線程在指定Condition對(duì)象上等待的時(shí)候,其實(shí)就是將線程包裝成結(jié)點(diǎn),加入了條件隊(duì)列,然后阻塞。當(dāng)線程被通知喚醒時(shí),則是將條件隊(duì)列中的結(jié)點(diǎn)轉(zhuǎn)換成等待隊(duì)列中的結(jié)點(diǎn),之后的處理就和獨(dú)占功能完全一樣。
除此之外,Condition還支持限時(shí)等待、非中斷等待等功能,分析思路是一樣的,讀者可以自己去閱讀AQS的源碼,通過使用示例,加入調(diào)試斷點(diǎn)一步步看內(nèi)部的調(diào)用流程,主干理順了之后,再看其它分支,其實(shí)是異曲同工的。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/76553.html
摘要:二接口簡(jiǎn)介可以看做是類的方法的替代品,與配合使用。當(dāng)線程執(zhí)行對(duì)象的方法時(shí),當(dāng)前線程會(huì)立即釋放鎖,并進(jìn)入對(duì)象的等待區(qū),等待其它線程喚醒或中斷。 showImg(https://segmentfault.com/img/remote/1460000016012601); 本文首發(fā)于一世流云的專欄:https://segmentfault.com/blog... 本系列文章中所說的juc-...
摘要:開始獲取鎖終于輪到出場(chǎng)了,的調(diào)用過程和完全一樣,同樣拿不到鎖,然后加入到等待隊(duì)列隊(duì)尾然后,在阻塞前需要把前驅(qū)結(jié)點(diǎn)的狀態(tài)置為,以確保將來可以被喚醒至此,的執(zhí)行也暫告一段落了安心得在等待隊(duì)列中睡覺。 showImg(https://segmentfault.com/img/remote/1460000016012467); 本文首發(fā)于一世流云的專欄:https://segmentfault...
摘要:好了,繼續(xù)向下執(zhí)行,嘗試獲取鎖失敗后,會(huì)調(diào)用首先通過方法,將包裝成共享結(jié)點(diǎn),插入等待隊(duì)列,插入完成后隊(duì)列結(jié)構(gòu)如下然后會(huì)進(jìn)入自旋操作,先嘗試獲取一次鎖,顯然此時(shí)是獲取失敗的主線程還未調(diào)用,同步狀態(tài)還是。 showImg(https://segmentfault.com/img/remote/1460000016012541); 本文首發(fā)于一世流云的專欄:https://segmentfa...
摘要:關(guān)于,最后有兩點(diǎn)規(guī)律需要注意當(dāng)?shù)牡却?duì)列隊(duì)首結(jié)點(diǎn)是共享結(jié)點(diǎn),說明當(dāng)前寫鎖被占用,當(dāng)寫鎖釋放時(shí),會(huì)以傳播的方式喚醒頭結(jié)點(diǎn)之后緊鄰的各個(gè)共享結(jié)點(diǎn)。當(dāng)?shù)牡却?duì)列隊(duì)首結(jié)點(diǎn)是獨(dú)占結(jié)點(diǎn),說明當(dāng)前讀鎖被使用,當(dāng)讀鎖釋放歸零后,會(huì)喚醒隊(duì)首的獨(dú)占結(jié)點(diǎn)。 showImg(https://segmentfault.com/img/remote/1460000016012293); 本文首發(fā)于一世流云的專欄:...
摘要:公平策略在多個(gè)線程爭(zhēng)用鎖的情況下,公平策略傾向于將訪問權(quán)授予等待時(shí)間最長(zhǎng)的線程。使用方式的典型調(diào)用方式如下二類原理的源碼非常簡(jiǎn)單,它通過內(nèi)部類實(shí)現(xiàn)了框架,接口的實(shí)現(xiàn)僅僅是對(duì)的的簡(jiǎn)單封裝,參見原理多線程進(jìn)階七鎖框架獨(dú)占功能剖析 showImg(https://segmentfault.com/img/remote/1460000016012582); 本文首發(fā)于一世流云的專欄:https...
閱讀 1981·2019-08-30 15:54
閱讀 3608·2019-08-29 13:07
閱讀 3132·2019-08-29 12:39
閱讀 1799·2019-08-26 12:13
閱讀 1555·2019-08-23 18:31
閱讀 2167·2019-08-23 18:05
閱讀 1856·2019-08-23 18:00
閱讀 1052·2019-08-23 17:15