国产亚洲精品福利在线无卡一,国产精久久一区二区三区,亚洲精品无码国模,精品久久久久久无码专区不卡

當(dāng)前位置: 首頁 > news >正文

玉溪網(wǎng)絡(luò)推廣 網(wǎng)站建設(shè)國外網(wǎng)站加速

玉溪網(wǎng)絡(luò)推廣 網(wǎng)站建設(shè),國外網(wǎng)站加速,做寢室介紹網(wǎng)站,企業(yè)微信公眾號平臺官網(wǎng)前言 相關(guān)系列 《Java & Lock & 目錄》(持續(xù)更新)《Java & Lock & ConditionObject & 源碼》(學(xué)習(xí)過程/多有漏誤/僅作參考/不再更新)《Java & Lock & ConditionObject & 總結(jié)》(學(xué)習(xí)…

前言


?相關(guān)系列

  • 《Java & Lock & 目錄》(持續(xù)更新)
  • 《Java & Lock & ConditionObject & 源碼》(學(xué)習(xí)過程/多有漏誤/僅作參考/不再更新)
  • 《Java & Lock & ConditionObject & 總結(jié)》(學(xué)習(xí)總結(jié)/最新最準(zhǔn)/持續(xù)更新)
  • 《Java & Lock & ConditionObject & 問題》(學(xué)習(xí)解答/持續(xù)更新)
    ?

?涉及內(nèi)容

  • 《Java & Lock & 總結(jié)》
  • 《Java & Lock & Condition & 總結(jié)》
  • 《Java & Lock & LockSupport & 總結(jié)》
    ?
    ?

概述


?簡介

????ConditionObject @ 條件對象類用于管理AQS訪問線程。條件對象類是AQS類對條件接口的內(nèi)部實(shí)現(xiàn),同時(shí)也是Java JDK對條件接口的唯一實(shí)現(xiàn)。條件接口被Java設(shè)計(jì)用來定義條件機(jī)制,條件機(jī)制的本質(zhì)是線程管理機(jī)制,用于在并發(fā)環(huán)境下實(shí)現(xiàn)對線程的有序協(xié)調(diào)及精確控制,即令線程有序的等待/喚醒。AQS類通過對條件機(jī)制的引入/實(shí)現(xiàn)對外提供了一套可控制自身訪問線程的基礎(chǔ)手段,使得開發(fā)者可以根據(jù)不同需求/環(huán)境/規(guī)則對AQS訪問線程進(jìn)行邏輯控制。

/*** Condition implementation for a {@link AbstractQueuedSynchronizer} serving as the basis of a {@link Lock}* implementation.* AQS的條件實(shí)現(xiàn)用于充當(dāng)鎖實(shí)現(xiàn)的基礎(chǔ)。* <p>* Method documentation for this class describes mechanics, not behavioral specifications from the point of view of* Lock and Condition users. Exported versions of this class will in general need to be accompanied by documentation* describing condition semantics that rely on those of the associated {@code AbstractQueuedSynchronizer}.* 該類的方法文檔從鎖和條件用戶的角度描述了機(jī)制,而不是行為規(guī)范。這個(gè)類的導(dǎo)出版本通常需要附帶描述依賴于相* 關(guān)AbstractQueuedSynchronizer的條件語義的文檔。* <p>* This class is Serializable, but all fields are transient, so deserialized conditions have no waiters.* 該類是序列化的,但所有字段被修飾了transient,所以反序列化的條件沒有等待者。*/
public class ConditionObject implements Condition, Serializable {...
}

????條件對象類用于對暫時(shí)失去同步意愿的線程進(jìn)行管理。我們可能會對“條件對象類用于管理AQS訪問線程”這一說法產(chǎn)生疑惑,因?yàn)锳QS類本身就是一套協(xié)調(diào)/控制線程的線程管理機(jī)制,為什么還要在其基礎(chǔ)上額外引入條件機(jī)制呢?這是因?yàn)锳QS類專用于對有同步意愿的線程進(jìn)行管理,即其只能管理想要/已被同步的線程。但實(shí)際情況是線程可能在某些情況下暫時(shí)失去同步意愿,但又因?yàn)闀换謴?fù)而繼續(xù)對AQS保持訪問狀態(tài),從而使得AQS類無法管理此類線程,因此才需要引入/實(shí)現(xiàn)條件機(jī)制對之進(jìn)行管理。

????線程暫時(shí)失去同步意愿的實(shí)際場景有且僅有暫時(shí)解除同步一種,相應(yīng)場景如下:

具有同步意愿:線程一/多次通過AQS達(dá)成同步/獲取[state @ 狀態(tài)];
失去同步意愿:線程在同步后執(zhí)行邏輯,后因條件未達(dá)成而暫停并暫時(shí)解除同步/徹底釋放[狀態(tài)],隨后被安排進(jìn)入條件對象中等待恢復(fù)同步;
恢復(fù)同步意愿:線程因?yàn)闂l件達(dá)成而被喚醒并恢復(fù)同步/一次性獲取釋放的所有[狀態(tài)],隨后從邏輯暫停處繼續(xù)執(zhí)行邏輯。

????條件對象類只支持對獨(dú)占線程進(jìn)行管理。通過上文所述場景我們可知線程為了等待某些條件達(dá)成會暫時(shí)解除同步,但與此同時(shí)我們可能產(chǎn)生新的疑惑:等待條件達(dá)成與暫時(shí)解除同步之間存在何種聯(lián)系?為什么線程要在等待的過程中暫時(shí)解除同步呢?這是因?yàn)闂l件的達(dá)成可能需要由其它線程在同步時(shí)實(shí)現(xiàn),因此如果在該情況下獨(dú)占線程不暫時(shí)解除同步,則其將因?yàn)闂l件無法達(dá)成而永久等待。暫時(shí)解除同步后的獨(dú)占線程會交由條件對象負(fù)責(zé)管理(等待/喚醒)。那為什么說條件對象類只支持對獨(dú)占線程進(jìn)行管理呢?這是因?yàn)閷τ诠蚕砭€程來說,由于設(shè)計(jì)上允許其它共享線程并行同步的原因,條件完全可以在不解除同步的情況下達(dá)成,因此條件對象類不支持也不需要對共享線程進(jìn)行管理。

????條件對象類是非靜態(tài)的公共類。條件對象類是公共類意味著開發(fā)者可以通過常規(guī)的new關(guān)鍵字創(chuàng)建條件對象,而非靜態(tài)則是一個(gè)需要特別注意的點(diǎn),因?yàn)檫@意味著條件對象并非與AQS類關(guān)聯(lián)而是與具體的AQS關(guān)聯(lián),而這就側(cè)面表示了條件對象類對獨(dú)占線程的管理是分批而非統(tǒng)一的,即每個(gè)條件對象只能管理自身所屬AQS的獨(dú)占線程而無法對其它AQS的獨(dú)占線程進(jìn)行管理。
?
?

方法


?等待

  • public final void await() throws InterruptedException —— 等待 —— 令已獨(dú)占同步當(dāng)前AQS的當(dāng)前線程原子性地解除同步并在當(dāng)前條件對象中進(jìn)入等待狀態(tài)。該方法是等待方法“阻塞”形式的實(shí)現(xiàn),當(dāng)前線程會無限等待至因?yàn)樾盘柖鴨拘褳橹共⒅匦禄謴?fù)對當(dāng)前AQS的獨(dú)占同步至初始狀態(tài)。當(dāng)前線程在進(jìn)入方法/等待恢復(fù)期間如果已/被中斷會拋出中斷異常,但中斷狀態(tài)會被清除。

  • public final void awaitUninterruptibly() —— 等待(不可中斷) —— 令已獨(dú)占同步當(dāng)前AQS的當(dāng)前線程原子性地解除同步并在當(dāng)前條件對象中進(jìn)入等待狀態(tài)。該方法是等待方法“阻塞不可中斷”形式的實(shí)現(xiàn),當(dāng)前線程會無限等待至因?yàn)樾盘柖鴨拘褳橹共⒅匦禄謴?fù)對當(dāng)前AQS的獨(dú)占同步至初始狀態(tài)。當(dāng)前線程在進(jìn)入方法/等待恢復(fù)期間如果已/被中斷不會拋出中斷異常,但中斷狀態(tài)會被保留。

  • public final boolean await(long time, TimeUnit unit) throws InterruptedException —— 等待 —— 令已獨(dú)占同步當(dāng)前AQS的當(dāng)前線程原子性地解除同步并在當(dāng)前條件對象中進(jìn)入等待狀態(tài)。該方法是等待方法“超時(shí)”形式的實(shí)現(xiàn)之一,當(dāng)前線程會有限等待至因?yàn)樾盘柖鴨拘褳橹共⒃谥匦禄謴?fù)對當(dāng)前AQS的獨(dú)占同步至初始狀態(tài)后返回true,超時(shí)指定等待時(shí)間則返回false。當(dāng)前線程在進(jìn)入方法/等待恢復(fù)期間如果已/被中斷會拋出中斷異常,但中斷狀態(tài)會被清除。

  • public final long awaitNanos(long nanosTimeout) throws InterruptedException —— 等待納秒 —— 令已獨(dú)占同步當(dāng)前AQS的當(dāng)前線程原子性地解除同步并在當(dāng)前條件對象中進(jìn)入等待狀態(tài)。該方法是等待方法“超時(shí)”形式的實(shí)現(xiàn)之一,當(dāng)前線程會有限等待至因?yàn)樾盘柖鴨拘褳橹共⒃谥匦禄謴?fù)對當(dāng)前AQS的獨(dú)占同步至初始狀態(tài)后返回剩余等待納秒,超時(shí)指定等待時(shí)間則返回0或負(fù)數(shù)。當(dāng)前線程在進(jìn)入方法/等待恢復(fù)期間如果已/被中斷會拋出中斷異常,但中斷狀態(tài)會被清除。

  • public final boolean awaitUntil(Date deadline) throws InterruptedException —— 等待 —— 令已獨(dú)占同步當(dāng)前AQS的當(dāng)前線程原子性地解除同步并在當(dāng)前條件對象中進(jìn)入等待狀態(tài)。該方法是等待方法“超時(shí)”形式的實(shí)現(xiàn)之一,當(dāng)前線程會有限等待至因?yàn)樾盘柖鴨拘褳橹共⒃谥匦禄謴?fù)對當(dāng)前AQS的獨(dú)占同步至初始狀態(tài)后返回true,超時(shí)指定等待時(shí)間則返回false。當(dāng)前線程在進(jìn)入方法/等待恢復(fù)期間如果已/被中斷會拋出中斷異常,但中斷狀態(tài)會被清除。
    ?

?信號

  • public void signal() —— 信號 —— 喚醒一條在當(dāng)前條件對象中等待的線程以令之重新恢復(fù)對當(dāng)前AQS的獨(dú)占持有。

  • public void signalAll() —— 信號全部 —— 喚醒所有在當(dāng)前條件對象中等待的線程以令之重新恢復(fù)對當(dāng)前AQS的獨(dú)占持有。
    ?
    ?

實(shí)現(xiàn)


?條件隊(duì)列

在這里插入圖片描述
????條件對象類采用條件隊(duì)列管理暫時(shí)解除同步的獨(dú)占線程。出于公平喚醒及共用節(jié)點(diǎn)類等原因,條件對象類采用與AQS類相似的隊(duì)列結(jié)構(gòu)來管理獨(dú)占線程,該隊(duì)列被稱為條件隊(duì)列。條件隊(duì)列與同步隊(duì)列一樣都是邏輯隊(duì)列,條件對象類使用[firstWaiter/lastWaiter @ 首個(gè)等待者/最后等待者]來持有條件隊(duì)列頭/尾獨(dú)占節(jié)點(diǎn)的引用,從而變相持有整個(gè)條件隊(duì)列。雖說與同步隊(duì)列共用節(jié)點(diǎn)類,但條件隊(duì)列并不使用[前驅(qū)/后繼節(jié)點(diǎn)]鏈接獨(dú)占節(jié)點(diǎn):一是因?yàn)闂l件隊(duì)列是單向鏈表,獨(dú)占節(jié)點(diǎn)并不需要持有前驅(qū)引用;二是因?yàn)楠?dú)占節(jié)點(diǎn)存在同時(shí)位于同步/條件隊(duì)列的情況,因此為了支持該情況也必須使用不同的字段來持有其在兩類隊(duì)列中的后繼引用。該知識點(diǎn)在AQS類的相應(yīng)文章中已經(jīng)提及過,此處再進(jìn)行詳細(xì)闡述:獨(dú)占節(jié)點(diǎn)使用[nextWaiter @ 模式/后繼等待者]持有其在條件隊(duì)列中的后繼引用,而由于只有獨(dú)占節(jié)點(diǎn)才可能加入條件隊(duì)列,因此該使用方式并不會與[模式/后繼等待者]原本表示模式的功能設(shè)計(jì)產(chǎn)生沖突。

????獨(dú)占節(jié)點(diǎn)的[模式/后繼等待者]未必一定為<EXCLUSIVE @ 獨(dú)占 @ null>。AQS類的文章在講解節(jié)點(diǎn)時(shí)說過AQS類使用<獨(dú)占>和<SHARED @ 獨(dú)占 @ node>兩個(gè)靜態(tài)常量節(jié)點(diǎn)作為表示獨(dú)占/共享模式的標(biāo)記,因此當(dāng)[模式/后繼等待者]為<獨(dú)占>時(shí)便意味著其為獨(dú)占節(jié)點(diǎn)…但實(shí)際上該說法并不準(zhǔn)確…因?yàn)榫驮趧偛盼覀兲岬搅霜?dú)占節(jié)點(diǎn)存在同時(shí)位于同步/條件隊(duì)列的情況,而又因?yàn)楠?dú)占節(jié)點(diǎn)使用[模式/后繼等待者]持有其在條件隊(duì)列中的后繼引用,因此[模式/后繼等待者]也完全可以在同步隊(duì)列中持有具體引用。那能否說[模式/后繼等待者]為<獨(dú)占>就表示獨(dú)占節(jié)點(diǎn)只位于同步隊(duì)列中呢?也不可以…因?yàn)楫?dāng)獨(dú)占節(jié)點(diǎn)恰好為條件隊(duì)列的尾節(jié)點(diǎn)時(shí)其[模式/后繼等待者]也一樣為<獨(dú)占>,因此想要準(zhǔn)確判斷節(jié)點(diǎn)是否為獨(dú)占模式實(shí)際上只能通過查看[模式/后繼等待者]是否不為<共享>判斷。

????一個(gè)AQS可能關(guān)聯(lián)多個(gè)條件隊(duì)列。與同步隊(duì)列只有一個(gè)不同,一個(gè)AQS可能關(guān)聯(lián)了多個(gè)條件隊(duì)列。這并不是說條件隊(duì)列可以在條件對象中存在多個(gè),而是AQS類允許基于一個(gè)AQS創(chuàng)建多個(gè)條件對象。該特性使得開發(fā)者可以進(jìn)一步細(xì)化對獨(dú)占線程的管理,即即使是同屬于一個(gè)AQS的獨(dú)占線程也可以通過調(diào)用不同條件對象來進(jìn)行分批管理,只要條件對象基于該AQS創(chuàng)建即可。
?

?等待/暫時(shí)解除同步

????條件對象類將線程同步的暫時(shí)解除與等待進(jìn)行了合并。AQS類通過條件對象類的等待方法令獨(dú)占線程暫時(shí)解除同步,即當(dāng)獨(dú)占線程調(diào)用條件對象的等待方法時(shí)會同時(shí)完成暫時(shí)解除同步及等待兩項(xiàng)功能。因此條件對象類不單單只是負(fù)責(zé)對獨(dú)占線程的管理,還是令獨(dú)占線程暫時(shí)解除同步的操作入口。

????獨(dú)占線程會自封為獨(dú)占節(jié)點(diǎn)尾插至條件隊(duì)列中。當(dāng)獨(dú)占線程調(diào)用等待方法暫時(shí)解除同步時(shí),其會將自身封裝為[waitStatus @ 等待狀態(tài)]為<CONDITION @ -2 @ 條件>的獨(dú)占節(jié)點(diǎn)并尾插至條件隊(duì)列中。整個(gè)尾插過程并不需要CAS的保護(hù),因?yàn)榇藭r(shí)的獨(dú)占線程尚未解除同步,故而在此期間不會有其它獨(dú)占線程參與競爭而導(dǎo)致線程安全問題。那是否存在獨(dú)占節(jié)點(diǎn)直接從同步隊(duì)列遷移至條件隊(duì)列的情況呢?這個(gè)問題確實(shí)值得思考,因?yàn)楠?dú)占線程在其位于同步隊(duì)列等待同步的過程中暫時(shí)失去同步意愿似乎也是有可能的…但很遺憾這種情況并不存在。上文已經(jīng)說過,目前關(guān)于獨(dú)占線程暫時(shí)失去同步意愿的具體場景只存在暫時(shí)解除同步一種,而對于已同步的獨(dú)占線程來說即使其曾經(jīng)確實(shí)被安排加入過同步隊(duì)列以等待同步,也會在成功同步后斷開與其所屬獨(dú)占節(jié)點(diǎn)的關(guān)聯(lián)。因此即使其所屬獨(dú)占節(jié)點(diǎn)依舊以[head @ 頭節(jié)點(diǎn)]的形式存在于同步隊(duì)列中,獨(dú)占線程也必然已從同步隊(duì)列中脫離,故而加入條件隊(duì)列的獨(dú)占節(jié)點(diǎn)必然是全新創(chuàng)建的。

????獨(dú)占線程可能在加入條件隊(duì)列前觸發(fā)對條件隊(duì)列的清理。在將自身封裝為獨(dú)占節(jié)點(diǎn)并加入條件隊(duì)列之前,獨(dú)占線程會先判斷尾節(jié)點(diǎn)是否存在且是否為取消節(jié)點(diǎn),是則觸發(fā)對條件隊(duì)列的清理。該知識點(diǎn)會在下文講解取消時(shí)詳述,此處之所以會特別提及源于該觸發(fā)時(shí)機(jī)屬于“彌補(bǔ)”性質(zhì),即專用于處理執(zhí)行清理的獨(dú)占線程在某些情況下無法判斷獨(dú)占節(jié)點(diǎn)是否位于條件隊(duì)列中的情況。

????獨(dú)占線程會在成功加入條件隊(duì)列后暫時(shí)解除同步。暫時(shí)解除同步的本質(zhì)是徹底釋放所有[狀態(tài)]并喚醒同步隊(duì)列的首個(gè)非空節(jié)點(diǎn)[線程],這里強(qiáng)調(diào)徹底是因?yàn)楠?dú)占線程可能因?yàn)橹厝攵?jīng)歷過多次同步。但無論其達(dá)成同步/獲取[狀態(tài)]多少次在暫時(shí)解除同步時(shí)都會被一次性釋放,以使得其它獨(dú)占線程獲得被同步的可能。暫時(shí)解除同步可能失敗,原因是其底層調(diào)用的tryRelease(int arg)方法由AQS類子類負(fù)責(zé)實(shí)現(xiàn),因此無法保證[狀態(tài)]徹底釋放的必然成功。條件隊(duì)列中獨(dú)占線程會在暫時(shí)解除同步失敗(理論上不允許失敗)時(shí)拋出非法監(jiān)視器狀態(tài)異常,但獨(dú)占節(jié)點(diǎn)則會在[等待狀態(tài)]會被賦值為<CANCELLED @ 1 @ 取消>后繼續(xù)保留在條件隊(duì)列中等待被清理,這也是獨(dú)占節(jié)點(diǎn)在條件隊(duì)列中唯一會被顯式取消的情況。

????獨(dú)占線程會在暫時(shí)解除同步后進(jìn)入有限/無限等待狀態(tài)。獨(dú)占線程進(jìn)入有限/無限等待狀態(tài)的本質(zhì)是LockSupport.park(…)方法的自我調(diào)用,該內(nèi)容的關(guān)鍵在于無論何種形式的等待方法都必須以循環(huán)的方式調(diào)用LockSupport.park(…)方法以滿足“實(shí)現(xiàn)需求設(shè)計(jì)”與“避免虛假喚醒”兩方面的要求。以“實(shí)現(xiàn)需求設(shè)計(jì)”舉例:對于不可中斷形式的等待方法而言,如果獨(dú)占線程被中斷喚醒,則獨(dú)占線程可以通過循環(huán)再次進(jìn)入有限/無限等待狀態(tài)以避免在自身?xiàng)l件未達(dá)成時(shí)恢復(fù)同步。條件對象類將“獨(dú)占節(jié)點(diǎn)不位于同步隊(duì)列中”作為等待循環(huán)的判斷條件,原因是將獨(dú)占節(jié)點(diǎn)從條件隊(duì)列遷移至同步隊(duì)列只會在符合需求設(shè)計(jì)的喚醒前/后發(fā)生,例如條件達(dá)成時(shí)的信號喚醒前;又例如可中斷/定時(shí)的等待方法中發(fā)生的中斷/超時(shí)喚醒后等,因此獨(dú)占節(jié)點(diǎn)位于同步隊(duì)列中便意味著獨(dú)占線程已無需/不許再繼續(xù)等待,從而退出等待循環(huán)。

????“避免虛假喚醒”也是等待必須循環(huán)執(zhí)行的必要理由。虛假喚醒是一種發(fā)生于LockSupport.park(…)方法的奇妙現(xiàn)象,具體表現(xiàn)為因LockSupport.park(…)方法而進(jìn)入有限/無限等待狀態(tài)的線程可能在毫無理由的情況下被喚醒。虛假喚醒并不屬于符合需求設(shè)計(jì)的喚醒,因此其發(fā)生前/后都不應(yīng)該遷移獨(dú)占節(jié)點(diǎn),故而如果不輔以循環(huán),獨(dú)占線程將可能在不符合業(yè)務(wù)的情況下提前結(jié)束等待,而這顯然是不允許的。事實(shí)上由于虛假喚醒這一奇妙現(xiàn)象的存在,將LockSupport.park(…)方法置于相應(yīng)邏輯的循環(huán)中執(zhí)行才是官方指定的正確調(diào)用方式。

????判斷獨(dú)占節(jié)點(diǎn)是否位于同步隊(duì)列中并不十分耗時(shí)。條件對象類通過調(diào)用AQS類的isOnSyncQueue(Node node)方法判斷獨(dú)占節(jié)點(diǎn)是否位于同步隊(duì)列中,而其操作本質(zhì)是以[尾節(jié)點(diǎn)]/獨(dú)占節(jié)點(diǎn)為起/終點(diǎn)的前遍歷查找行為。當(dāng)獨(dú)占節(jié)點(diǎn)已遷移至同步隊(duì)列中時(shí),由于同步隊(duì)列是尾插法,又因?yàn)檫w移與喚醒(無論兩者前后順序如何)是緊密相連的操作/時(shí)間間隔非常短,因此在獨(dú)占線程前遍歷查找時(shí)獨(dú)占節(jié)點(diǎn)通常就位于同步隊(duì)列的尾部附近,故而并不十分耗時(shí)。那如果獨(dú)占節(jié)點(diǎn)尚未被遷移至同步隊(duì)列中呢?豈不是要進(jìn)行全遍歷?這難道還不耗時(shí)么?的確按正常邏輯來說如果在同步隊(duì)列中等待同步的線程非常多的話那確實(shí)將是一項(xiàng)非常耗時(shí)的操作…但這并非是無法彌補(bǔ)的。AQS類采用了多項(xiàng)優(yōu)化方案避免獨(dú)占線程在查找所屬獨(dú)占節(jié)點(diǎn)時(shí)全遍歷同步隊(duì)列,這些優(yōu)化方案可以對獨(dú)占節(jié)點(diǎn)位于/不位于同步隊(duì)列的大部分情況進(jìn)行快速篩選,從而使得全遍歷行為只在少數(shù)極端條件下執(zhí)行…優(yōu)化策略具體如下:

判斷獨(dú)占節(jié)點(diǎn)的[等待狀態(tài)]是否為<條件> —— <條件>是獨(dú)占節(jié)點(diǎn)"只"位于條件隊(duì)列中時(shí)才可能存在的狀態(tài),當(dāng)獨(dú)占節(jié)點(diǎn)被遷移至同步隊(duì)列時(shí)其[等待狀態(tài)]會被賦值為0,因此如果發(fā)現(xiàn)獨(dú)占節(jié)點(diǎn)的[等待狀態(tài)]為<條件>便意味著其必然不位于同步隊(duì)列中;

判斷獨(dú)占節(jié)點(diǎn)的[前驅(qū)節(jié)點(diǎn)]是否為null —— 獨(dú)占節(jié)點(diǎn)的[前驅(qū)節(jié)點(diǎn)]為null意味著獨(dú)占節(jié)點(diǎn)不位于或以[頭節(jié)點(diǎn)]的形式存在于同步隊(duì)列中。由于此時(shí)的獨(dú)占線程尚未恢復(fù)同步,因此其所屬獨(dú)占節(jié)點(diǎn)不可能成為[頭節(jié)點(diǎn)],因此如果獨(dú)占節(jié)點(diǎn)的[前驅(qū)節(jié)點(diǎn)]為null便意味著其必然不位于同步隊(duì)列中;

判斷獨(dú)占節(jié)點(diǎn)的[后繼節(jié)點(diǎn)]是否不為null —— 獨(dú)占節(jié)點(diǎn)的[后繼節(jié)點(diǎn)]為null并不代表其一定不位于同步隊(duì)列中,因?yàn)橥疥?duì)列[尾節(jié)點(diǎn)][后繼節(jié)點(diǎn)]也為null,但如果獨(dú)占節(jié)點(diǎn)的[后繼節(jié)點(diǎn)]不為null便意味著其必然位于同步隊(duì)列中。
?

?信號喚醒

????在條件隊(duì)列中有限/無限等待的獨(dú)占線程會因?yàn)樾盘?中斷/超時(shí)/虛假四種原因被喚醒。我們已知虛假喚醒是需求設(shè)計(jì)所不允許的特殊情況,并也已通過等待循環(huán)的方式彌補(bǔ),因此關(guān)于喚醒的核心內(nèi)容會集中在其它三種喚醒操作上。事實(shí)上這三種喚醒操作單獨(dú)講解起來都并不復(fù)雜,但關(guān)鍵在于三者是允許交錯(cuò)并發(fā)的,這就要求條件對象類必須能夠在復(fù)雜的并發(fā)場景中準(zhǔn)確查明/分辨出獨(dú)占線程被喚醒的真實(shí)原因以對外作出正確反饋,而這才是喚醒操作的真正難點(diǎn)所在。事實(shí)上想要判斷得知獨(dú)占線程被喚醒的真實(shí)原因是難以/無法做到的,原因是缺乏可靠的判斷依據(jù),因此條件對象類采用“標(biāo)記”方案定性獨(dú)占線程的喚醒方式?!皹?biāo)記”方案的核心為搶占,即當(dāng)多種喚醒操作并發(fā)時(shí)獨(dú)占線程會被定性為被優(yōu)先標(biāo)記的喚醒方式喚醒,因此獨(dú)占線程的實(shí)際喚醒方式與標(biāo)記喚醒方式可能并不相同,該知識點(diǎn)會在下文講解三種喚醒操作時(shí)詳述。

????“信號喚醒”只能由正在同步的獨(dú)占線程執(zhí)行。成功同步的獨(dú)占線程可以通過調(diào)用信號方法中的signal()方法喚醒在條件隊(duì)列中等待的首個(gè)獨(dú)占節(jié)點(diǎn)[thread @ 線程],此外其還可以調(diào)用signalAll()方法喚醒在條件隊(duì)列中等待的所有獨(dú)占線程。signalAll()方法會遍歷條件隊(duì)列并依次喚醒所有的獨(dú)占線程,這在效果上與循環(huán)調(diào)用signal()方法是等價(jià)的,但避免了一些非必要的操作。

????“信號喚醒”可能因?yàn)槭《貜?fù)執(zhí)行?!靶盘枂拘选笔〉脑蚴且?yàn)楠?dú)占線程已被并發(fā)標(biāo)記為中斷/超時(shí)喚醒,由于喚醒方法存在必須令等待中的獨(dú)占線程會被信號喚醒的定義,因此失敗時(shí)signal()方法會重新定位新首個(gè)獨(dú)占線程以再次執(zhí)行“信號喚醒”,直至喚醒成功或無首個(gè)獨(dú)占節(jié)點(diǎn)[線程]可被喚醒為止。

????“信號喚醒”會嘗試將獨(dú)占節(jié)點(diǎn)的[等待狀態(tài)]由<條件>CAS賦值為0,該CAS被稱為標(biāo)記CAS。標(biāo)記CAS并非只是單純的CAS賦值,而是所有喚醒操作都必須執(zhí)行的關(guān)鍵步驟,其作用具體有四:一是將[等待狀態(tài)]還原為初始狀態(tài)0以備獨(dú)占節(jié)點(diǎn)加入同步隊(duì)列;二是將獨(dú)占線程的喚醒方式標(biāo)記為自身;三是判斷獨(dú)占節(jié)點(diǎn)是否已被取消;四是判斷獨(dú)占線程是否已被標(biāo)記為被其它喚醒方式喚醒。

????獨(dú)占節(jié)點(diǎn)最初會以<條件>的[等待狀態(tài)]加入條件隊(duì)列,又因?yàn)閇等待狀態(tài)]會在獨(dú)占線程暫時(shí)解除同步失敗時(shí)被顯式賦值為<取消>,因此標(biāo)記CAS失敗就意味著獨(dú)占節(jié)點(diǎn)可能已被取消;此外由于所有的喚醒都會執(zhí)行標(biāo)記CAS,因此失敗還意味著獨(dú)占線程可能已被標(biāo)記為被其它喚醒方式喚醒;最后如果標(biāo)記CAS成功,則意味著獨(dú)占線程已被標(biāo)記被當(dāng)前喚醒方式喚醒,因?yàn)槠渌鼏拘巡僮鞯臉?biāo)記CAS會因?yàn)楫?dāng)前喚醒操作的標(biāo)記CAS成功而失敗。但請注意!獨(dú)占線程被標(biāo)記為指定的喚醒只是近似的模擬,是因?yàn)闊o法準(zhǔn)確探知而選取的最大可能,并不意味著獨(dú)占線程實(shí)際就是被標(biāo)記的喚醒方式所喚醒…例如下表中就展示了獨(dú)占線程被中斷/超時(shí)喚醒但又被標(biāo)記為信號喚醒的情況:

信號喚醒中斷/超時(shí)喚醒
T01獨(dú)占線程因?yàn)橹袛?超時(shí)而喚醒
T02將獨(dú)占節(jié)點(diǎn)[等待狀態(tài)]由<條件>CAS賦值為0成功,獨(dú)占線程被標(biāo)記為信號喚醒
T03將獨(dú)占節(jié)點(diǎn)[等待狀態(tài)]由<條件>CAS賦值為0失敗,認(rèn)定獨(dú)占線程已被信號喚醒

????被成功標(biāo)記CAS的獨(dú)占節(jié)點(diǎn)會被遷移至同步隊(duì)列以重新競爭同步/恢復(fù)同步意愿。被標(biāo)記為信號喚醒的獨(dú)占線程會將所屬獨(dú)占節(jié)點(diǎn)從條件隊(duì)列中遷移至同步隊(duì)列,即獨(dú)占節(jié)點(diǎn)會從條件隊(duì)列中頭部移除并尾插至同步隊(duì)列中。獨(dú)占節(jié)點(diǎn)被遷移至同步隊(duì)列意味著獨(dú)占線程重新參與了對同步的競爭,并由此宣告其正式恢復(fù)同步意愿。需要重點(diǎn)提及是:由于獨(dú)占節(jié)點(diǎn)在加入同步隊(duì)列前會從條件隊(duì)列的頭部移除,即會將[模式/后繼等待者]置null以斷開與條件隊(duì)列的關(guān)聯(lián),因此“信號喚醒”中被遷移的獨(dú)占節(jié)點(diǎn)只存在于同步隊(duì)列中。但除此以外,被遷移的獨(dú)占節(jié)點(diǎn)還有同時(shí)存在于同步/條件隊(duì)列的情況,該知識點(diǎn)會在下文講解中斷/超時(shí)喚醒時(shí)詳述。

????“信號喚醒”的核心是“遷移”而非“喚醒”,其只保證獨(dú)占線程必然會被喚醒,但不保證由執(zhí)行“信號喚醒”的同步獨(dú)占線程執(zhí)行。獨(dú)占節(jié)點(diǎn)被遷移至同步隊(duì)列后,此時(shí)的獨(dú)占線程依然處于有限/無限等待狀態(tài),并且未必會被立即信號喚醒,即“信號喚醒”并非一定會對獨(dú)占線程執(zhí)行LockSupport.unpark(Thread thread)方法。之所以會如此是因?yàn)楠?dú)占節(jié)點(diǎn)加入同步隊(duì)列后獨(dú)占線程為了等待同步也需要進(jìn)入有限/無限等待狀態(tài),因此“信號喚醒”通常不需要將其喚醒,只需放任其等待“狀態(tài)喚醒”即可。當(dāng)然情況也并非完全如此,在兩種情況下“信號喚醒”也需要喚醒獨(dú)占線程:一是獨(dú)占節(jié)點(diǎn)的[前驅(qū)節(jié)點(diǎn)]為取消節(jié)點(diǎn),這是出于令獨(dú)占線程執(zhí)行“等待 - 前驅(qū)式清理”的目的;二是在“狀態(tài)喚醒”執(zhí)行線程將獨(dú)占節(jié)點(diǎn)[前驅(qū)節(jié)點(diǎn)]的[等待狀態(tài)]由0CAS賦值為<SIGNAL @ -1 @ 信號>失敗時(shí),因?yàn)檫@可能導(dǎo)致獨(dú)占線程永遠(yuǎn)無法被喚醒,是與取消CAS相同性質(zhì)的行為,因此需要將之信號喚醒以執(zhí)行“等待 - 等待CAS”操作。
?

?中斷/超時(shí)喚醒

????被喚醒的獨(dú)占線程會第一時(shí)間判斷自身是否已被中斷。無論實(shí)際喚醒方式及等待方法的形式為何,獨(dú)占線程被喚醒后都會第一時(shí)間通過響應(yīng)中斷的方式判斷自身是否已被中斷,這么做的目的是確定自身是否具有被中斷喚醒的可能,并以此為依據(jù)執(zhí)行“中斷喚醒”,故而“中斷喚醒”的執(zhí)行者實(shí)際上是被喚醒的獨(dú)占線程本身。

????“中斷喚醒”會執(zhí)行標(biāo)記CAS。當(dāng)標(biāo)記CAS成功時(shí),被標(biāo)記為中斷喚醒的獨(dú)占線程會遷移獨(dú)占節(jié)點(diǎn)至同步隊(duì)列中以重新競爭同步/恢復(fù)同步意愿,因此與“信號喚醒”不同,“中斷喚醒”中的獨(dú)占線程是以喚醒的形態(tài)被遷移至同步隊(duì)列的,并且遷移也位于獨(dú)占線程被喚醒之后。此外需要特別注意的是:“中斷喚醒”在遷移獨(dú)占節(jié)點(diǎn)時(shí)并不會將其從條件隊(duì)列中移除,原因是該獨(dú)占節(jié)點(diǎn)未必與“信號喚醒”中的獨(dú)占節(jié)點(diǎn)一樣是條件隊(duì)列的頭節(jié)點(diǎn),即不一定是[首個(gè)等待者],因此想要移除就必須先對條件隊(duì)列進(jìn)行遍歷查找,而這顯然是不高效也不安全的行為。因?yàn)檫@即可能導(dǎo)致頻繁的長遍歷,又可能因?yàn)槎嗒?dú)占線程并發(fā)中斷遷移而導(dǎo)致部分獨(dú)占節(jié)點(diǎn)被遺留在條件隊(duì)列中…因此也就直接導(dǎo)致了獨(dú)占節(jié)點(diǎn)同時(shí)位于同步/條件隊(duì)列情況的產(chǎn)生。

在這里插入圖片描述

????“中斷喚醒”的標(biāo)記CAS失敗意味著獨(dú)占線程已被并發(fā)標(biāo)記為信號喚醒,在這種實(shí)際被中斷喚醒但又被標(biāo)記為信號喚醒的情況下獨(dú)占線程會額外判斷/保證獨(dú)占節(jié)點(diǎn)在自身退出等待循環(huán)前必然位于同步隊(duì)列中。之所以要進(jìn)行額外判斷/保證是因?yàn)楠?dú)占線程會在確認(rèn)自身被中斷后不經(jīng)下次的等待判斷而直接退出當(dāng)前等待循環(huán),而又因?yàn)椤靶盘枂拘选睂Κ?dú)占節(jié)點(diǎn)的遷移位于標(biāo)記CAS之后,因此此時(shí)的獨(dú)占節(jié)點(diǎn)[等待狀態(tài)]雖然已被CAS賦值為0,但可能尚未被遷移至同步隊(duì)列中。而由于獨(dú)占線程正處于喚醒狀態(tài),因此當(dāng)其退出等待循環(huán)并嘗試獲取[狀態(tài)]時(shí)將可能因?yàn)楠?dú)占節(jié)點(diǎn)不位于同步隊(duì)列/沒有[前驅(qū)節(jié)點(diǎn)]而拋出NullPointerException @ 空指針異?!嚓P(guān)源碼及模擬異常場景如下:

while (!isOnSyncQueue(node)) {LockSupport.park(this);// ---- 獨(dú)占線程在確定自身被中斷后會直接退出等到循環(huán),因此checkInterruptWhileWaiting方法中包含了響應(yīng)中斷和遷移保障的邏輯。if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)break;
}
信號喚醒/同步線程中斷/獨(dú)占線程
T01因?yàn)橹袛喽粏拘?#xff0c;并發(fā)現(xiàn)自身被中斷
T02執(zhí)行標(biāo)記CAS成功執(zhí)行標(biāo)記CAS失敗
T03直接退出等待循環(huán)
T04嘗試獲取[狀態(tài)]并因?yàn)楠?dú)占節(jié)點(diǎn)不位于同步隊(duì)列/沒有[前驅(qū)節(jié)點(diǎn)]而拋出空指針異常
T05將獨(dú)占節(jié)點(diǎn)從條件隊(duì)列遷移至同步隊(duì)列

????獨(dú)占線程通過yield()方法保證所屬獨(dú)占節(jié)點(diǎn)在其退出等待循環(huán)前必然位于同步隊(duì)列中。當(dāng)獨(dú)占線程在額外判斷中發(fā)現(xiàn)獨(dú)占節(jié)點(diǎn)未位于同步隊(duì)列時(shí)會短暫放棄CPU資源以期望自身再次獲取CPU資源時(shí)獨(dú)占節(jié)點(diǎn)已加入同步隊(duì)列,由于該行為無法保證必然性,因此yield()方法同樣需要循環(huán)執(zhí)行。

while (!isOnSyncQueue(node))Thread.yield();

????在定時(shí)形式的等待方法中如果獨(dú)占線程被喚醒后發(fā)現(xiàn)自身沒有被標(biāo)記為中斷/信號喚醒,則會在下個(gè)循環(huán)中判斷自身是否有被超時(shí)喚醒的可能。獨(dú)占線程通過查看是否存在剩余等待時(shí)間判斷其是否可能被超時(shí)喚醒,這種可能在剩余等待時(shí)間不存在時(shí)成立,因此該情況下獨(dú)占線程會執(zhí)行“超時(shí)喚醒”…關(guān)鍵源碼如下:

while (!isOnSyncQueue(node)) {// ---- 判斷是否已經(jīng)超時(shí),超時(shí)的優(yōu)先級比等待和中斷更高,因此被超時(shí)喚醒的獨(dú)占線程只// 能在下次循環(huán)中判斷超時(shí)。而在這個(gè)過程中獨(dú)占線程可能被標(biāo)記為信號/中斷喚醒。if (nanosTimeout <= 0L) {timedout = transferAfterCancelledWait(node);break;}// ---- 在等待時(shí)間剩余較多的情況下等待,否則直接自旋。if (nanosTimeout >= spinForTimeoutThreshold)LockSupport.parkNanos(this, nanosTimeout);// ---- 獨(dú)占線程在確定自身被中斷后會直接退出等到循環(huán)。if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)break;nanosTimeout = deadline - System.nanoTime();
}

????“超時(shí)喚醒”與“中斷喚醒”在流程上是相同的?!俺瑫r(shí)”及“中斷”兩種喚醒操作底層都調(diào)用transferAfterCancelledWait(Node node)方法實(shí)現(xiàn),該方法用于執(zhí)行標(biāo)記CAS,并在成功后將獨(dú)占節(jié)點(diǎn)遷移至同步隊(duì)列,或在失敗后判斷/保證獨(dú)占線程在退出等待循環(huán)前令獨(dú)占節(jié)點(diǎn)位于同步隊(duì)列中。兩者的區(qū)別在于“超時(shí)喚醒”會直接調(diào)用該方法,而“中斷喚醒”則會在checkInterruptWhileWaiting(Node node)方法中確認(rèn)獨(dú)占線程被中斷后再間接調(diào)用該方法。從上述源碼中我們可以發(fā)現(xiàn)由于“超時(shí)喚醒”與“中斷喚醒”會先后執(zhí)行,因此對于一個(gè)獨(dú)占線程而言雖然中斷/超時(shí)喚醒之間確實(shí)可能并發(fā),但兩套操作卻不存在并發(fā)情況。而對于“信號喚醒”而言其雖然知道標(biāo)記CAS失敗是因?yàn)椤爸袛?超時(shí)喚醒”的原因,但卻不知道也沒必要知道具體是兩者中的哪一個(gè)所導(dǎo)致的。
?

?恢復(fù)同步

????被喚醒的獨(dú)占線程會恢復(fù)同步意愿。我們已知“信號/中斷/超時(shí)喚醒”會將獨(dú)占節(jié)點(diǎn)遷移至同步隊(duì)列中以令之重新競爭同步,由此宣告獨(dú)占線程正式恢復(fù)同步意愿。重新競爭同步與常規(guī)競爭同步最大的區(qū)別在于其會一次性獲取之前釋放的所有[狀態(tài)],從而將獨(dú)占線程的同步恢復(fù)到與暫時(shí)解除同步前完全一致的情況。此外重新競爭同步不會中斷/超時(shí),無論獨(dú)占線程最初是否調(diào)用了可中斷/定時(shí)形式的獲取方法來獲取同步,在重新競爭時(shí)都不會拋出中斷異?;蚍艞壨?#xff0c;因?yàn)橹袛?超時(shí)只作用于獨(dú)占線程首次達(dá)成同步的時(shí)候,該設(shè)計(jì)保證了獨(dú)占線程的同步必然可被恢復(fù)。

????被標(biāo)記為中斷喚醒的獨(dú)占線程會在恢復(fù)同步后拋出中斷異常。當(dāng)獨(dú)占線程再次經(jīng)歷競爭而恢復(fù)同步后,如果其被標(biāo)記為中斷喚醒,并且等待方法的形式允許中斷,則其會直接拋出中斷異常。一個(gè)值得思考的問題是:為什么獨(dú)占線程不直接在喚醒時(shí)拋出中斷異常而是在恢復(fù)同步后再拋出呢?實(shí)際上這是為了保證獨(dú)占線程同步的必然恢復(fù),以維護(hù)獨(dú)占線程對[狀態(tài)]的獲取/釋放必須成對出現(xiàn)的使用設(shè)定。事實(shí)上對于拋出中斷異常該行為可中斷形式的等待方法只允許兩種情況:一是在獨(dú)占線程尚未暫時(shí)解除同步時(shí)發(fā)生;二是在獨(dú)占線程恢復(fù)同步后發(fā)生。該兩者的核心都在于必須保證中斷異常拋出時(shí)獨(dú)占線程處于同步狀態(tài)。

????被中斷但未被標(biāo)記為中斷喚醒的獨(dú)占線程不會拋出中斷異常,但中斷狀態(tài)會被保留。在獨(dú)占線程被實(shí)際中斷喚醒但未被標(biāo)記中斷喚醒的情況下,無論并發(fā)場景為何,中斷都會被統(tǒng)一視作在獨(dú)占線程被喚醒后產(chǎn)生。而由于獨(dú)占線程未被標(biāo)記為中斷喚醒,因此該情況在需求設(shè)計(jì)上不滿足中斷異常的拋出條件,只會保留中斷狀態(tài)以表示獨(dú)占線程遭遇過中斷。此外如果等待方法的形式不允許中斷,則即使獨(dú)占線程被標(biāo)記為中斷喚醒也只會保留中斷狀態(tài)而不會拋出中斷異常。需要注意的是:被保留的中斷狀態(tài)屬于重中斷,是等待方法為了保留中斷狀態(tài)而額外執(zhí)行的中斷,原因是獨(dú)占線程無論是在暫時(shí)解除同步后的條件隊(duì)列中被中斷還是在恢復(fù)同步后的同步隊(duì)列中被中斷其中斷狀態(tài)都會因?yàn)橹袛嗯袛喽豁憫?yīng)消除。為此等待方法會記錄/整合兩個(gè)階段的中斷判斷結(jié)果為以下三種標(biāo)記,以作為其選擇中斷處理方案的依據(jù):

<REINTERRUPT @ 1 @ 重中斷>:表示獨(dú)占線程在條件隊(duì)列被中斷但未被標(biāo)記為中斷喚醒,以及在同步隊(duì)列中被中斷的標(biāo)記,該標(biāo)記意味著等待方法在退出時(shí)需要重中斷以保留中斷狀態(tài),因?yàn)楠?dú)占線程原本的中斷狀態(tài)會因?yàn)橹袛嗯袛喽豁憫?yīng)消除;

<0>:表示獨(dú)占線程未被中斷的標(biāo)識,該標(biāo)記意味著等待方法在退出時(shí)即不需要拋出中斷異常也不需要重中斷以保留中斷狀態(tài);

<THROW_IE @ -1 @ 拋出異常>:表示獨(dú)占線程條件隊(duì)列中被標(biāo)記中斷喚醒的標(biāo)記,該標(biāo)記意味著等待方法在退出時(shí)需要拋出中斷異常。

?

?取消

在這里插入圖片描述

????條件隊(duì)列中所有[等待狀態(tài)]不為<條件>的獨(dú)占節(jié)點(diǎn)都屬于取消節(jié)點(diǎn)。與同步隊(duì)列不同,除[等待狀態(tài)]被顯式賦值為<取消>的獨(dú)占節(jié)點(diǎn)屬于取消節(jié)點(diǎn)外,條件隊(duì)列中其它[等待狀態(tài)]不為<條件>的獨(dú)占節(jié)點(diǎn)也都會被視作隱式取消節(jié)點(diǎn)。由此可知被標(biāo)記為超時(shí)/中斷喚醒的獨(dú)占節(jié)點(diǎn)本質(zhì)上都屬于隱式取消節(jié)點(diǎn),因?yàn)檫@些獨(dú)占節(jié)點(diǎn)在標(biāo)記CAS后會直接加入同步隊(duì)列且不會從條件隊(duì)列中移除。而被標(biāo)記為信號喚醒的獨(dú)占節(jié)點(diǎn)由于會真正意義上的“遷移”因此不屬于取消節(jié)點(diǎn)的范圍…雖然其也會因?yàn)闃?biāo)記CAS和遷移之間存在時(shí)間間隔而短暫同時(shí)位于同步/條件隊(duì)列中,但由于時(shí)間過于短暫因此通常不在意這一點(diǎn)。

????隱式取消節(jié)點(diǎn)[線程]會全局清理?xiàng)l件隊(duì)列中的取消節(jié)點(diǎn)。隱式取消節(jié)點(diǎn)[線程]會在其恢復(fù)同步后,拋出中斷異常/重中斷之前遍歷性的全局清理?xiàng)l件隊(duì)列中的取消節(jié)點(diǎn),之所以只有隱式取消節(jié)點(diǎn)[線程]會在該時(shí)段執(zhí)行清理有兩點(diǎn)原因:一是因?yàn)轱@式取消節(jié)點(diǎn)[線程]會直接拋出非法監(jiān)視器狀態(tài)異常而無法執(zhí)行;二是如果令顯式取消節(jié)點(diǎn)[線程]也在此時(shí)執(zhí)行清理將導(dǎo)致大量的無用功。因?yàn)槿∠?jié)點(diǎn)通常與隱式取消節(jié)點(diǎn)在數(shù)量上等同,因此令隱式取消節(jié)點(diǎn)[線程]執(zhí)行清理就已足夠/過量滿足清理所需,無需再令顯式取消節(jié)點(diǎn)[線程]也執(zhí)行喚醒??梢园l(fā)現(xiàn)的是我們在進(jìn)行數(shù)量對比時(shí)并沒有考慮顯式取消節(jié)點(diǎn),因?yàn)橹灰险{(diào)用規(guī)范,暫時(shí)解除同步理論上是不應(yīng)該失敗的,因此顯式取消節(jié)點(diǎn)的產(chǎn)生本質(zhì)上屬于AQS類子類在實(shí)現(xiàn)上的缺陷,故而不納入計(jì)算范圍。

????隱式取消節(jié)點(diǎn)[線程]通過判斷[模式/后繼等待者]是否為null決定自身是否執(zhí)行清理。雖說上文在描述時(shí)一直使用“被標(biāo)記為**喚醒的獨(dú)占線程”這種說法,但實(shí)際上獨(dú)占線程并無法明確得知自身被標(biāo)記的喚醒方式,因?yàn)槠洳]有以字段的形式被保存下來。這大概率是出于節(jié)約內(nèi)存方面的考量,因?yàn)樵摂?shù)據(jù)在整體流程中并無作為準(zhǔn)確判斷依據(jù)的必要,原因是隱式取消節(jié)點(diǎn)[線程]可以通過查看[模式/后繼等待者]是否為null來代替判斷自身是否被標(biāo)記為中斷/超時(shí)喚醒。隱式取消節(jié)點(diǎn)[線程]會因?yàn)槠渌鶎俟?jié)點(diǎn)保留在條件隊(duì)列中而[模式/后繼等待者]不為null,因此[模式/后繼等待者]不為null便可作為隱式取消節(jié)點(diǎn)[線程]觸發(fā)清理的判斷依據(jù)。但該判斷方案并非是完美的,因?yàn)楫?dāng)取消節(jié)點(diǎn)為[最后等待者],即條件隊(duì)列的尾節(jié)點(diǎn)時(shí)其[模式/后繼等待者]也為null,因此在該情況下隱式取消節(jié)點(diǎn)[線程]對條件隊(duì)列的清理將不會被觸發(fā)。

????獨(dú)占線程可能在加入條件隊(duì)列前觸發(fā)對取消節(jié)點(diǎn)的清理。對于取消節(jié)點(diǎn)為[最后等待者]而無法觸發(fā)清理問題的處理方案其實(shí)在上文中已經(jīng)提及過了,即獨(dú)占線程可能在加入條件隊(duì)列前觸發(fā)對條件隊(duì)列的清理。獨(dú)占線程在將自身封裝為獨(dú)占節(jié)點(diǎn)并尾插至條件隊(duì)列前會先判斷[最后等待者]是否為取消節(jié)點(diǎn),是則先執(zhí)行清理以彌補(bǔ)上文的情況。我們由此可知獨(dú)占線程最多可能執(zhí)行兩次條件隊(duì)列清理,并且暫時(shí)解除同步失敗的線程也可能執(zhí)行清理,因?yàn)槠淇梢栽讵?dú)占節(jié)點(diǎn)入隊(duì)前觸發(fā)…但憑心而論該特殊處理顯得沒那么精妙,因?yàn)殡[式取消節(jié)點(diǎn)[線程]完全可以在發(fā)現(xiàn)[模式/后繼等待者]為null后再判斷所屬節(jié)點(diǎn)是否為[最后等待者]來執(zhí)行清理,而無需在入隊(duì)前判斷來提升代碼的復(fù)雜性…個(gè)人認(rèn)為這可能是因?yàn)楠?dú)占節(jié)點(diǎn)[線程]在入隊(duì)時(shí)原本就需要獲取[最后等待者]以作為其入隊(duì)基礎(chǔ)的原因,畢竟如此一來判斷[最后等待者]是否為取消節(jié)點(diǎn)就成為了順勢行為,從而避免隱式取消節(jié)點(diǎn)[線程]專門執(zhí)行這一點(diǎn)。

????條件隊(duì)列的清理是線程安全的,但無法保證取消節(jié)點(diǎn)全移除。無論是獨(dú)占線程加入條件隊(duì)列前/恢復(fù)同步后執(zhí)行的清理都具有一個(gè)特點(diǎn),即獨(dú)占線程都處于同步狀態(tài)。這意味著取消節(jié)點(diǎn)的清理是不會出現(xiàn)并發(fā)的,不會因?yàn)槎嗒?dú)占線程并發(fā)執(zhí)行而出現(xiàn)取消節(jié)點(diǎn)遺留的問題。但話說如此,取消節(jié)點(diǎn)遺留的現(xiàn)象是依然存在的,因?yàn)槿∠?jié)點(diǎn)的產(chǎn)生是允許并發(fā)的,畢竟超時(shí)/中斷喚醒并不會因?yàn)楫?dāng)前有獨(dú)占線程持有同步而停止。

http://m.aloenet.com.cn/news/41028.html

相關(guān)文章:

  • 寧波做日用品外貿(mào)公司網(wǎng)站百度搜索引擎原理
  • 湖北網(wǎng)站建設(shè)找哪家如何做好營銷推廣
  • asp.net網(wǎng)站安全太原網(wǎng)站制作優(yōu)化seo公司
  • 安順住房和城鄉(xiāng)建設(shè)部網(wǎng)站網(wǎng)站app開發(fā)公司
  • 昆山做網(wǎng)站的公司有哪些關(guān)鍵詞免費(fèi)
  • 德陽企業(yè)品牌網(wǎng)站建設(shè)seo網(wǎng)站推廣公司
  • 聚美優(yōu)品一個(gè)專注于做特價(jià)的網(wǎng)站活動(dòng)推廣軟文
  • 建站系統(tǒng)磁力搜索引擎不死鳥
  • 織夢做網(wǎng)站的教程短視頻代運(yùn)營合作方案
  • 吃什么補(bǔ)腎虛效果最好食物焦作整站優(yōu)化
  • 2018網(wǎng)站的建設(shè)與維護(hù)前景網(wǎng)店代運(yùn)營商
  • 鎮(zhèn)江做網(wǎng)站的做網(wǎng)站用什么編程軟件
  • 科技網(wǎng)站 網(wǎng)站建設(shè)廣告公司業(yè)務(wù)推廣
  • 網(wǎng)站開發(fā)需解決什么問題廣州百度關(guān)鍵詞搜索
  • 用html做班級網(wǎng)站萬網(wǎng)域名注冊信息查詢
  • 有道翻譯網(wǎng)站 做翻譯太原網(wǎng)站推廣排名
  • c做網(wǎng)站百度云登錄
  • wordpress首頁加登錄在線seo短視頻
  • 免費(fèi)學(xué)校網(wǎng)站管理系統(tǒng)南京百度seo排名
  • 有哪些做婚禮電子請柬的網(wǎng)站品牌推廣活動(dòng)策劃方案
  • 榆林免費(fèi)做網(wǎng)站推廣引流渠道
  • 如何做分類網(wǎng)站信息營銷市場調(diào)研一般怎么做
  • 惠州做網(wǎng)站 百度優(yōu)化線上宣傳渠道和宣傳方式
  • 達(dá)州網(wǎng)站建設(shè)公司電商引流推廣方法
  • wordpress 子目錄 404西安seo優(yōu)化公司
  • 網(wǎng)上建立網(wǎng)站網(wǎng)絡(luò)營銷策略分析方法
  • 網(wǎng)站解析什么意思建網(wǎng)站需要多少錢和什么條件
  • 網(wǎng)站名怎么寫整站優(yōu)化報(bào)價(jià)
  • 做機(jī)械的網(wǎng)站網(wǎng)站人多怎么優(yōu)化
  • 做汽車團(tuán)購的網(wǎng)站建設(shè)直通車推廣計(jì)劃方案