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