AQS隊(duì)列同步器

隊(duì)列同步器AbstractQueuedSynchronizer(以下簡(jiǎn)稱同步器)涮阔,是用來(lái)構(gòu)建鎖或者其他同步組件的基礎(chǔ)框架窿锉,它使用了一個(gè)int成員變量表示同步狀態(tài)起意,通過(guò)內(nèi)置的FIFO隊(duì)列來(lái)完成資源獲取線程的排隊(duì)工作凌彬,并發(fā)包的作者(Doug?Lea)期望它能夠成為實(shí)現(xiàn)大部分同步需求的基礎(chǔ)把介。

同步器的主要使用方式是繼承,子類通過(guò)繼承同步器并實(shí)現(xiàn)它的抽象方法來(lái)管理同步狀態(tài)厢漩,在抽象方法的實(shí)現(xiàn)過(guò)程中免不了要對(duì)同步狀態(tài)進(jìn)行更改膜眠,這時(shí)就需要使用同步器提供的3個(gè)方法(getState()、setState(int?newState)和compareAndSetState(int?expect,int?update))來(lái)進(jìn)行操作溜嗜,因?yàn)樗鼈兡軌虮WC狀態(tài)的改變是安全的宵膨。子類推薦被定義為自定義同步組件的靜態(tài)內(nèi)部類,同步器自身沒(méi)有實(shí)現(xiàn)任何同步接口炸宵,它僅僅是定義了若干同步狀態(tài)獲取和釋放的方法來(lái)供自定義同步組件使用辟躏,同步器既可以支持獨(dú)占式地獲取同步狀態(tài),也可以支持共享式地獲取同步狀態(tài)土全,這樣就可以方便實(shí)現(xiàn)不同類型的同步組件(ReentrantLock捎琐、?ReentrantReadWriteLock和CountDownLatch等)。

同步器是實(shí)現(xiàn)鎖(也可以是任意同步組件)的關(guān)鍵裹匙,在鎖的實(shí)現(xiàn)中聚合同步器瑞凑,利用同步器實(shí)現(xiàn)鎖的語(yǔ)義「乓常可以這樣理解二者之間的關(guān)系:鎖是面向使用者的籽御,它定義了使用者與鎖交互的接口(比如可以允許兩個(gè)線程并行訪問(wèn)),隱藏了實(shí)現(xiàn)細(xì)節(jié)惰匙;同步器面向的是鎖的實(shí)現(xiàn)者技掏,它簡(jiǎn)化了鎖的實(shí)現(xiàn)方式,屏蔽了同步狀態(tài)管理徽曲、線程的排隊(duì)零截、等待與喚醒等底層操作。鎖和同步器很好地隔離了使用者和實(shí)現(xiàn)者所需關(guān)注的領(lǐng)域秃臣。

隊(duì)列同步器的接口與示例

同步器的設(shè)計(jì)是基于模板方法模式的涧衙,也就是說(shuō),使用者需要繼承同步器并重寫(xiě)指定的方法奥此,隨后將同步器組合在自定義同步組件的實(shí)現(xiàn)中弧哎,并調(diào)用同步器提供的模板方法,而這些模板方法將會(huì)調(diào)用使用者重寫(xiě)的方法稚虎。

重寫(xiě)同步器指定的方法時(shí)撤嫩,需要使用同步器提供的如下3個(gè)方法來(lái)訪問(wèn)或修改同步狀態(tài)。

·getState():獲取當(dāng)前同步狀態(tài)蠢终。

·setState(int?newState):設(shè)置當(dāng)前同步狀態(tài)序攘。

·compareAndSetState(int?expect,int?update):使用CAS設(shè)置當(dāng)前狀態(tài)茴她,該方法能夠保證狀態(tài)設(shè)置的原子性。

同步器可重寫(xiě)的方法與描述如表所示程奠。

同步器可重寫(xiě)的方法

實(shí)現(xiàn)自定義同步組件時(shí)丈牢,將會(huì)調(diào)用同步器提供的模板方法,這些(部分)模板方法與描述如表所示瞄沙。

同步器提供的模板方法

同步器提供的模板方法基本上分為3類:獨(dú)占式獲取與釋放同步狀態(tài)己沛、共享式獲取與釋放同步狀態(tài)和查詢同步隊(duì)列中的等待線程情況。自定義同步組件將使用同步器提供的模板方法?來(lái)實(shí)現(xiàn)自己的同步語(yǔ)義距境。

只有掌握了同步器的工作原理才能更加深入地理解并發(fā)包中其他的并發(fā)組件申尼,所以下面通過(guò)一個(gè)獨(dú)占鎖的示例來(lái)深入了解一下同步器的工作原理。

顧名思義垫桂,獨(dú)占鎖就是在同一時(shí)刻只能有一個(gè)線程獲取到鎖师幕,而其他獲取鎖的線程只能處于同步隊(duì)列中等待,只有獲取鎖的線程釋放了鎖诬滩,后繼的線程才能夠獲取鎖们衙,如代碼所示。

上述示例中碱呼,獨(dú)占鎖Mutex是一個(gè)自定義同步組件,它在同一時(shí)刻只允許一個(gè)線程占有鎖宗侦。Mutex中定義了一個(gè)靜態(tài)內(nèi)部類愚臀,該內(nèi)部類繼承了同步器并實(shí)現(xiàn)了獨(dú)占式獲取和釋放同步?狀態(tài)。在tryAcquire(int?acquires)方法中矾利,如果經(jīng)過(guò)CAS設(shè)置成功(同步狀態(tài)設(shè)置為1姑裂,則代表獲取了同步狀態(tài),而在tryRelease(int?releases)方法中只是將同步狀態(tài)重置為0男旗。用戶使用Mutex時(shí)并不會(huì)直接和內(nèi)部同步器的實(shí)現(xiàn)打交道舶斧,而是調(diào)用Mutex提供的方法,在Mutex的實(shí)現(xiàn)中察皇,以獲取鎖的lock()方法為例茴厉,只需要在方法實(shí)現(xiàn)中調(diào)用同步器的模板方法acquire(int?args)即可,當(dāng)前線程調(diào)用該方法獲取同步狀態(tài)失敗后會(huì)被加入到同步隊(duì)列中等待什荣,這樣就大大降低了實(shí)現(xiàn)一個(gè)可靠自定義同步組件的門(mén)檻矾缓。

隊(duì)列同步器的實(shí)現(xiàn)分析

接下來(lái)將從實(shí)現(xiàn)角度分析同步器是如何完成線程同步的,主要包括:同步隊(duì)列稻爬、獨(dú)占式同步狀態(tài)獲取與釋放嗜闻、共享式同步狀態(tài)獲取與釋放以及超時(shí)獲取同步狀態(tài)等同步器的核心數(shù)據(jù)結(jié)構(gòu)與模板方法。

1.同步隊(duì)列

同步器依賴內(nèi)部的同步隊(duì)列(一個(gè)FIFO雙向隊(duì)列)來(lái)完成同步狀態(tài)的管理桅锄,當(dāng)前線程獲取同步狀態(tài)失敗時(shí)琉雳,同步器會(huì)將當(dāng)前線程以及等待狀態(tài)等信息構(gòu)造成為一個(gè)節(jié)點(diǎn)(Node)并將其加入同步隊(duì)列样眠,同時(shí)會(huì)阻塞當(dāng)前線程,當(dāng)同步狀態(tài)釋放時(shí)翠肘,會(huì)把首節(jié)點(diǎn)中的線程喚醒檐束,使其再次嘗試獲取同步狀態(tài)。

同步隊(duì)列中的節(jié)點(diǎn)(Node)用來(lái)保存獲取同步狀態(tài)失敗的線程引用锯茄、等待狀態(tài)以及前驅(qū)和后繼節(jié)點(diǎn)厢塘,節(jié)點(diǎn)的屬性類型與名稱以及描述如表所示。

節(jié)點(diǎn)是構(gòu)成同步隊(duì)列(等待隊(duì)列)的基礎(chǔ)肌幽,同步器擁有首節(jié)點(diǎn)(head)?和尾節(jié)點(diǎn)(tail)晚碾,沒(méi)有成功獲取同步狀態(tài)的線程將會(huì)成為節(jié)點(diǎn)加入該隊(duì)列的尾部,同步隊(duì)列的基本結(jié)構(gòu)如圖所示喂急。

同步隊(duì)列的基本結(jié)構(gòu)

在上圖中格嘁,同步器包含了兩個(gè)節(jié)點(diǎn)類型的引用,一個(gè)指向頭節(jié)點(diǎn)廊移,而另一個(gè)指向尾節(jié)點(diǎn)糕簿。試想一下,當(dāng)一個(gè)線程成功地獲取了同步狀態(tài)(或者鎖)狡孔,其他線程將無(wú)法獲取到同步狀態(tài)懂诗,轉(zhuǎn)而被構(gòu)造成為節(jié)點(diǎn)并加入到同步隊(duì)列中,而這個(gè)加入隊(duì)列的過(guò)程必須要保證線程安全苗膝,因此同步器提供了一個(gè)基于CAS的設(shè)置尾節(jié)點(diǎn)的方法:compareAndSetTail(Node???????expect,Node?update)殃恒,它需要傳遞當(dāng)前線程“認(rèn)為”的尾節(jié)點(diǎn)和當(dāng)前節(jié)點(diǎn),只有設(shè)置成功后辱揭,當(dāng)前節(jié)點(diǎn)才正式與之前的尾節(jié)點(diǎn)建立關(guān)聯(lián)离唐。

同步器將節(jié)點(diǎn)加入到同步隊(duì)列的過(guò)程如圖所示。

節(jié)點(diǎn)加入到同步隊(duì)列

同步隊(duì)列遵循FIFO问窃,首節(jié)點(diǎn)是獲取同步狀態(tài)成功的節(jié)點(diǎn)亥鬓,首節(jié)點(diǎn)的線程在釋放同步狀態(tài)時(shí),將會(huì)喚醒后繼節(jié)點(diǎn)域庇,而后繼節(jié)點(diǎn)將會(huì)在獲取同步狀態(tài)成功時(shí)將自己設(shè)置為首節(jié)點(diǎn)嵌戈,該過(guò)程如圖所示。

首節(jié)點(diǎn)的設(shè)置

在上圖中较剃,設(shè)置首節(jié)點(diǎn)是通過(guò)獲取同步狀態(tài)成功的線程來(lái)完成的咕别,由于只有一個(gè)線程能夠成功獲取到同步狀態(tài),因此設(shè)置頭節(jié)點(diǎn)的方法并不需要使用CAS來(lái)保證写穴,它只需要將首節(jié)點(diǎn)設(shè)置成為原首節(jié)點(diǎn)的后繼節(jié)點(diǎn)并斷開(kāi)原首節(jié)點(diǎn)的next引用即可惰拱。

獨(dú)占式同步狀態(tài)獲取與釋放

通過(guò)調(diào)用同步器的acquire(int?arg)方法可以獲取同步狀態(tài),該方法對(duì)中斷不敏感,也就是由于線程獲取同步狀態(tài)失敗后進(jìn)入同步隊(duì)列中偿短,后續(xù)對(duì)線程進(jìn)行中斷操作時(shí)欣孤,線程不會(huì)從同步隊(duì)列中移出,該方法代碼如下所示昔逗。

上述代碼主要完成了同步狀態(tài)獲取降传、節(jié)點(diǎn)構(gòu)造、加入同步隊(duì)列以及在同步隊(duì)列中自旋等待的相關(guān)工作勾怒,其主要邏輯是:首先調(diào)用自定義同步器實(shí)現(xiàn)的tryAcquire(int??arg)方法婆排,該方法保證線程安全的獲取同步狀態(tài),如果同步狀態(tài)獲取失敗笔链,則構(gòu)造同步節(jié)點(diǎn)(獨(dú)占式?Node.EXCLUSIVE段只,同一時(shí)刻只能有一個(gè)線程成功獲取同步狀態(tài))并通過(guò)addWaiter(Node???????node)?方法將該節(jié)點(diǎn)加入到同步隊(duì)列的尾部,最后調(diào)用acquireQueued(Node?node,int?arg)方法鉴扫,使得該節(jié)點(diǎn)以“死循環(huán)”的方式獲取同步狀態(tài)赞枕。如果獲取不到則阻塞節(jié)點(diǎn)中的線程,而被阻塞線程的喚醒主要依靠前驅(qū)節(jié)點(diǎn)的出隊(duì)或阻塞線程被中斷來(lái)實(shí)現(xiàn)坪创。

下面分析一下相關(guān)工作炕婶。首先是節(jié)點(diǎn)的構(gòu)造以及加入同步隊(duì)列,如下代碼所示莱预。

上述代碼通過(guò)使用compareAndSetTail(Node?expect,Node?update)方法來(lái)確保節(jié)點(diǎn)能夠被線程安全添加柠掂。試想一下:如果使用一個(gè)普通的LinkedList來(lái)維護(hù)節(jié)點(diǎn)之間的關(guān)系,那么當(dāng)一個(gè)線程獲取了同步狀態(tài)依沮,而其他多個(gè)線程由于調(diào)用tryAcquire(int?arg)方法獲取同步狀態(tài)失敗而并發(fā)地被添加到LinkedList時(shí)陪踩,LinkedList將難以保證Node的正確添加,最終的結(jié)果可能是節(jié)點(diǎn)的數(shù)量有偏差悉抵,而且順序也是混亂的。

在enq(final?Node?node)方法中摘完,同步器通過(guò)“死循環(huán)”來(lái)保證節(jié)點(diǎn)的正確添加姥饰,在“死循環(huán)”中只有通過(guò)CAS將節(jié)點(diǎn)設(shè)置成為尾節(jié)點(diǎn)之后,當(dāng)前線程才能從該方法返回孝治,否則列粪,當(dāng)前線程不斷地嘗試設(shè)置√胳可以看出岂座,enq(final?Node?node)方法將并發(fā)添加節(jié)點(diǎn)的請(qǐng)求通過(guò)CAS變得“串行化”了。

節(jié)點(diǎn)進(jìn)入同步隊(duì)列之后杭措,就進(jìn)入了一個(gè)自旋的過(guò)程费什,每個(gè)節(jié)點(diǎn)(或者說(shuō)每個(gè)線程)都在自省地觀察,當(dāng)條件滿足手素,獲取到了同步狀態(tài)鸳址,就可以從這個(gè)自旋過(guò)程中退出瘩蚪,否則依舊留在這個(gè)自旋過(guò)程中(并會(huì)阻塞節(jié)點(diǎn)的線程),如代碼所示稿黍。

在acquireQueued(final?Node?node,int?arg)方法中疹瘦,當(dāng)前線程在“死循環(huán)”中嘗試獲取同步狀態(tài),而只有前驅(qū)節(jié)點(diǎn)是頭節(jié)點(diǎn)才能夠嘗試獲取同步狀態(tài)巡球,這是為什么言沐?原因有兩個(gè),如下酣栈。

第一险胰,頭節(jié)點(diǎn)是成功獲取到同步狀態(tài)的節(jié)點(diǎn),而頭節(jié)點(diǎn)的線程釋放了同步狀態(tài)之后钉嘹,將會(huì)

喚醒其后繼節(jié)點(diǎn)鸯乃,后繼節(jié)點(diǎn)的線程被喚醒后需要檢查自己的前驅(qū)節(jié)點(diǎn)是否是頭節(jié)點(diǎn)。

第二跋涣,維護(hù)同步隊(duì)列的FIFO原則缨睡。該方法中,節(jié)點(diǎn)自旋獲取同步狀態(tài)的行為如圖所示陈辱。

節(jié)點(diǎn)自旋獲取同步狀態(tài)

在上圖中奖年,由于非首節(jié)點(diǎn)線程前驅(qū)節(jié)點(diǎn)出隊(duì)或者被中斷而從等待狀態(tài)返回,隨后檢查自己的前驅(qū)是否是頭節(jié)點(diǎn)沛贪,如果是則嘗試獲取同步狀態(tài)陋守。可以看到節(jié)點(diǎn)和節(jié)點(diǎn)之間在循環(huán)檢查的過(guò)程中基本不相互通信利赋,而是簡(jiǎn)單地判斷自己的前驅(qū)是否為頭節(jié)點(diǎn)水评,這樣就使得節(jié)點(diǎn)的釋放規(guī)則符合FIFO,并且也便于對(duì)過(guò)早通知的處理(過(guò)早通知是指前驅(qū)節(jié)點(diǎn)不是頭節(jié)點(diǎn)的線程由于中斷而被喚醒)媚送。

獨(dú)占式同步狀態(tài)獲取流程中燥,也就是acquire(int?arg)方法調(diào)用流程,如圖所示塘偎。

在上圖中疗涉,前驅(qū)節(jié)點(diǎn)為頭節(jié)點(diǎn)且能夠獲取同步狀態(tài)的判斷條件和線程進(jìn)入等待狀態(tài)是獲取同步狀態(tài)的自旋過(guò)程。當(dāng)同步狀態(tài)獲取成功之后吟秩,當(dāng)前線程從acquire(int?arg)方法返回咱扣,如果對(duì)于鎖這種并發(fā)組件而言,代表著當(dāng)前線程獲取了鎖涵防。

當(dāng)前線程獲取同步狀態(tài)并執(zhí)行了相應(yīng)邏輯之后闹伪,就需要釋放同步狀態(tài),使得后續(xù)節(jié)點(diǎn)能夠繼續(xù)獲取同步狀態(tài)。通過(guò)調(diào)用同步器的release(int?arg)方法可以釋放同步狀態(tài)祭往,該方法在釋放了同步狀態(tài)之后伦意,會(huì)喚醒其后繼節(jié)點(diǎn)(進(jìn)而使后繼節(jié)點(diǎn)重新嘗試獲取同步狀態(tài))。該方法代碼如下所示硼补。

該方法執(zhí)行時(shí)驮肉,會(huì)喚醒頭節(jié)點(diǎn)的后繼節(jié)點(diǎn)線程,unparkSuccessor(Node?node)方法使用?LockSupport來(lái)喚醒處于等待狀態(tài)的線程已骇。

分析了獨(dú)占式同步狀態(tài)獲取和釋放過(guò)程后离钝,適當(dāng)做個(gè)總結(jié):在獲取同步狀態(tài)時(shí),同步器維護(hù)一個(gè)同步隊(duì)列褪储,獲取狀態(tài)失敗的線程都會(huì)被加入到隊(duì)列中并在隊(duì)列中進(jìn)行自旋卵渴;移出隊(duì)列

(或停止自旋)的條件是前驅(qū)節(jié)點(diǎn)為頭節(jié)點(diǎn)且成功獲取了同步狀態(tài)。在釋放同步狀態(tài)時(shí)鲤竹,同步器調(diào)用tryRelease(int?arg)方法釋放同步狀態(tài)浪读,然后喚醒頭節(jié)點(diǎn)的后繼節(jié)點(diǎn)。

共享式同步狀態(tài)獲取與釋放

共享式獲取與獨(dú)占式獲取最主要的區(qū)別在于同一時(shí)刻能否有多個(gè)線程同時(shí)獲取到同步狀態(tài)辛藻。以文件的讀寫(xiě)為例碘橘,如果一個(gè)程序在對(duì)文件進(jìn)行讀操作,那么這一時(shí)刻對(duì)于該文件的寫(xiě)操作均被阻塞吱肌,而讀操作能夠同時(shí)進(jìn)行痘拆。寫(xiě)操作要求對(duì)資源的獨(dú)占式訪問(wèn)烂翰,而讀操作可以是共享式訪問(wèn)叫搁,兩種不同的訪問(wèn)模式在同一時(shí)刻對(duì)文件或資源的訪問(wèn)情況,如圖所示污筷。

共享式與獨(dú)占式訪問(wèn)資源的對(duì)比

在上圖中规揪,左半部分桥氏,共享式訪問(wèn)資源時(shí),其他共享式的訪問(wèn)均被允許猛铅,而獨(dú)占式訪問(wèn)被阻塞识颊,右半部分是獨(dú)占式訪問(wèn)資源時(shí),同一時(shí)刻其他訪問(wèn)均被阻塞奕坟。

通過(guò)調(diào)用同步器的acquireShared(int?arg)方法可以共享式地獲取同步狀態(tài),該方法代碼如下所示清笨。

在acquireShared(int?arg)方法中月杉,同步器調(diào)用tryAcquireShared(int?arg)方法嘗試獲取同步狀態(tài),tryAcquireShared(int?arg)方法返回值為int類型抠艾,當(dāng)返回值大于等于0時(shí)苛萎,表示能夠獲取到同步狀態(tài)。因此,在共享式獲取的自旋過(guò)程中腌歉,成功獲取到同步狀態(tài)并退出自旋的條件就是?tryAcquireShared(int?arg)方法返回值大于等于0蛙酪。可以看到翘盖,在doAcquireShared(int?arg)方法的自旋過(guò)程中桂塞,如果當(dāng)前節(jié)點(diǎn)的前驅(qū)為頭節(jié)點(diǎn)時(shí),嘗試獲取同步狀態(tài)馍驯,如果返回值大于等于0阁危,表示該次獲取同步狀態(tài)成功并從自旋過(guò)程中退出。

與獨(dú)占式一樣汰瘫,共享式獲取也需要釋放同步狀態(tài)狂打,通過(guò)調(diào)用releaseShared(int?arg)方法可以

釋放同步狀態(tài),該方法代碼如下所示混弥。

該方法在釋放同步狀態(tài)之后趴乡,將會(huì)喚醒后續(xù)處于等待狀態(tài)的節(jié)點(diǎn)。對(duì)于能夠支持多個(gè)線程同時(shí)訪問(wèn)的并發(fā)組件(比如Semaphore)蝗拿,它和獨(dú)占式主要區(qū)別在于tryReleaseShared(int?arg)?方法必須確保同步狀態(tài)(或者資源數(shù))線程安全釋放晾捏,一般是通過(guò)循環(huán)和CAS來(lái)保證的,因?yàn)獒尫磐綘顟B(tài)的操作會(huì)同時(shí)來(lái)自多個(gè)線程蛹磺。

獨(dú)占式超時(shí)獲取同步狀態(tài)

通過(guò)調(diào)用同步器的doAcquireNanos(int?arg,long?nanosTimeout)方法可以超時(shí)獲取同步狀態(tài)粟瞬,即在指定的時(shí)間段內(nèi)獲取同步狀態(tài),如果獲取到同步狀態(tài)則返回true萤捆,否則裙品,返回false。該方法提供了傳統(tǒng)Java同步操作(比如synchronized關(guān)鍵字)所不具備的特性俗或。

在分析該方法的實(shí)現(xiàn)前市怎,先介紹一下響應(yīng)中斷的同步狀態(tài)獲取過(guò)程。在Java?5之前辛慰,當(dāng)一個(gè)線程獲取不到鎖而被阻塞在synchronized之外時(shí)区匠,對(duì)該線程進(jìn)行中斷操作,此時(shí)該線程的中斷標(biāo)志位會(huì)被修改帅腌,但線程依舊會(huì)阻塞在synchronized上驰弄,等待著獲取鎖。在Java?5中速客,同步器提供了acquireInterruptibly(int?arg)方法戚篙,這個(gè)方法在等待獲取同步狀態(tài)時(shí),如果當(dāng)前線程被中斷溺职,會(huì)立刻返回岔擂,并拋出InterruptedException位喂。

超時(shí)獲取同步狀態(tài)過(guò)程可以被視作響應(yīng)中斷獲取同步狀態(tài)過(guò)程的“增強(qiáng)版”,?doAcquireNanos(int?arg,long?nanosTimeout)方法在支持響應(yīng)中斷的基礎(chǔ)上乱灵,增加了超時(shí)獲取的特性塑崖。針對(duì)超時(shí)獲取,主要需要計(jì)算出需要睡眠的時(shí)間間隔nanosTimeout痛倚,為了防止過(guò)早通知规婆,?nanosTimeout計(jì)算公式為:nanosTimeout-=now-lastTime,其中now為當(dāng)前喚醒時(shí)間状原,lastTime為上次喚醒時(shí)間聋呢,如果nanosTimeout大于0則表示超時(shí)時(shí)間未到,需要繼續(xù)睡眠nanosTimeout納秒颠区,反之削锰,表示已經(jīng)超時(shí),該方法代碼如下所示毕莱。

該方法在自旋過(guò)程中器贩,當(dāng)節(jié)點(diǎn)的前驅(qū)節(jié)點(diǎn)為頭節(jié)點(diǎn)時(shí)嘗試獲取同步狀態(tài),如果獲取成功則從該方法返回朋截,這個(gè)過(guò)程和獨(dú)占式同步獲取的過(guò)程類似蛹稍,但是在同步狀態(tài)獲取失敗的處理上有所不同。如果當(dāng)前線程獲取同步狀態(tài)失敗部服,則判斷是否超時(shí)(nanosTimeout小于等于0表示已經(jīng)超時(shí))唆姐,如果沒(méi)有超時(shí),重新計(jì)算超時(shí)間隔nanosTimeout廓八,然后使當(dāng)前線程等待?nanosTimeout納秒(當(dāng)已到設(shè)置的超時(shí)時(shí)間奉芦,該線程會(huì)從LockSupport.parkNanos(Object?blocker,long?nanos)方法返回)。

如果nanosTimeout小于等于spinForTimeoutThreshold(1000納秒)時(shí)剧蹂,將不會(huì)使該線程進(jìn)行超時(shí)等待声功,而是進(jìn)入快速的自旋過(guò)程。原因在于宠叼,非常短的超時(shí)等待無(wú)法做到十分精確先巴,如果這時(shí)再進(jìn)行超時(shí)等待,相反會(huì)讓nanosTimeout的超時(shí)從整體上表現(xiàn)得反而不精確冒冬。因此伸蚯,在超時(shí)非常短的場(chǎng)景下,同步器會(huì)進(jìn)入無(wú)條件的快速自旋简烤。

獨(dú)占式超時(shí)獲取同步態(tài)的流程如圖所示剂邮。

獨(dú)占式超時(shí)獲取同步狀態(tài)的流程

從圖中可以看出,獨(dú)占式超時(shí)獲取同步狀態(tài)doAcquireNanos(int?arg,long?nanosTimeout)?和獨(dú)占式獲取同步狀態(tài)acquire(int?args)在流程上非常相似乐埠,其主要區(qū)別在于未獲取到同步狀態(tài)時(shí)的處理邏輯抗斤。acquire(int?args)在未獲取到同步狀態(tài)時(shí),將會(huì)使當(dāng)前線程一直處于等待狀態(tài)丈咐,而doAcquireNanos(int?arg,long?nanosTimeout)會(huì)使當(dāng)前線程等待nanosTimeout納秒瑞眼,如果當(dāng)?前線程在nanosTimeout納秒內(nèi)沒(méi)有獲取到同步狀態(tài),將會(huì)從等待邏輯中自動(dòng)返回棵逊。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末伤疙,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子辆影,更是在濱河造成了極大的恐慌徒像,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,542評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蛙讥,死亡現(xiàn)場(chǎng)離奇詭異锯蛀,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)次慢,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,596評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門(mén)旁涤,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人迫像,你說(shuō)我怎么就攤上這事劈愚。” “怎么了闻妓?”我有些...
    開(kāi)封第一講書(shū)人閱讀 158,021評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵菌羽,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我由缆,道長(zhǎng)注祖,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,682評(píng)論 1 284
  • 正文 為了忘掉前任犁功,我火速辦了婚禮氓轰,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘浸卦。我一直安慰自己署鸡,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,792評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布限嫌。 她就那樣靜靜地躺著靴庆,像睡著了一般。 火紅的嫁衣襯著肌膚如雪怒医。 梳的紋絲不亂的頭發(fā)上炉抒,一...
    開(kāi)封第一講書(shū)人閱讀 49,985評(píng)論 1 291
  • 那天,我揣著相機(jī)與錄音稚叹,去河邊找鬼焰薄。 笑死拿诸,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的塞茅。 我是一名探鬼主播亩码,決...
    沈念sama閱讀 39,107評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼野瘦!你這毒婦竟也來(lái)了描沟?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,845評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤鞭光,失蹤者是張志新(化名)和其女友劉穎吏廉,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體惰许,經(jīng)...
    沈念sama閱讀 44,299評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡席覆,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,612評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了啡省。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片娜睛。...
    茶點(diǎn)故事閱讀 38,747評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖卦睹,靈堂內(nèi)的尸體忽然破棺而出畦戒,到底是詐尸還是另有隱情,我是刑警寧澤结序,帶...
    沈念sama閱讀 34,441評(píng)論 4 333
  • 正文 年R本政府宣布障斋,位于F島的核電站,受9級(jí)特大地震影響徐鹤,放射性物質(zhì)發(fā)生泄漏垃环。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,072評(píng)論 3 317
  • 文/蒙蒙 一返敬、第九天 我趴在偏房一處隱蔽的房頂上張望遂庄。 院中可真熱鬧,春花似錦劲赠、人聲如沸涛目。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,828評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)霹肝。三九已至,卻和暖如春塑煎,著一層夾襖步出監(jiān)牢的瞬間沫换,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,069評(píng)論 1 267
  • 我被黑心中介騙來(lái)泰國(guó)打工最铁, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留讯赏,地道東北人垮兑。 一個(gè)月前我還...
    沈念sama閱讀 46,545評(píng)論 2 362
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像漱挎,于是被迫代替她去往敵國(guó)和親甥角。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,658評(píng)論 2 350

推薦閱讀更多精彩內(nèi)容