隊(duì)列是一種特殊的線性表,特殊之處在于它只允許在表的前端(front)進(jìn)行刪除操作,而在表的后端(rear)進(jìn)行插入操作,和棧一樣,隊(duì)列是一種操作受限制的線性表。進(jìn)行插入操作的端稱為隊(duì)尾,進(jìn)行刪除操作的端稱為隊(duì)頭。
專注于為中小企業(yè)提供成都網(wǎng)站設(shè)計(jì)、網(wǎng)站建設(shè)服務(wù),電腦端+手機(jī)端+微信端的三站合一,更高效的管理,為中小企業(yè)福田免費(fèi)做網(wǎng)站提供優(yōu)質(zhì)的服務(wù)。我們立足成都,凝聚了一批互聯(lián)網(wǎng)行業(yè)人才,有力地推動(dòng)了1000+企業(yè)的穩(wěn)健成長(zhǎng),幫助中小企業(yè)通過網(wǎng)站建設(shè)實(shí)現(xiàn)規(guī)模擴(kuò)充和轉(zhuǎn)變。
在隊(duì)列中插入一個(gè)隊(duì)列元素稱為入隊(duì),從隊(duì)列中刪除一個(gè)隊(duì)列元素稱為出隊(duì)。因?yàn)殛?duì)列只允許在一端插入,在另一端刪除,所以只有最早進(jìn)入隊(duì)列的元素才能最先從隊(duì)列中刪除,故隊(duì)列又稱為先進(jìn)先出(FIFO—first in first out)線性表。
阻塞隊(duì)列常用于生產(chǎn)者和消費(fèi)者的場(chǎng)景,生產(chǎn)者是向隊(duì)列里添加元素的線程,消費(fèi)者是從隊(duì)列里取元素的線程。阻塞隊(duì)列就是生產(chǎn)者用來存放元素、消費(fèi)者用來獲取元素的容器。
阻塞隊(duì)列在jdk中有個(gè)專門的接口,BlockingQueue。但BlockingQueue的方法并不都是阻塞的方法:
add()插入元素,remove()拿取元素。add()往一個(gè)滿的隊(duì)列中插元素會(huì)插不進(jìn),會(huì)拋出異常;而remove()從空隊(duì)列拿,也會(huì)拋出異常。
offer()和poll(),往一個(gè)滿的隊(duì)列,返回一個(gè)false;poll()往一個(gè)空隊(duì)列中取元素,返回一個(gè)null
take()、put(),真正體現(xiàn)BlockingQueue的阻塞
take()往一個(gè)滿的隊(duì)列中插元素會(huì)阻塞;put()往一個(gè)空隊(duì)列中取元素,也會(huì)阻塞
以上的阻塞隊(duì)列都實(shí)現(xiàn)了BlockingQueue接口,也都是線程安全的。
是一個(gè)用數(shù)組實(shí)現(xiàn)的有界阻塞隊(duì)列。此隊(duì)列按照先進(jìn)先出的原則對(duì)元素進(jìn)行排序。默認(rèn)情況下不保證線程公平的訪問隊(duì)列,所謂公平訪問隊(duì)列是指阻塞的線程,可以按照阻塞的先后順序訪問隊(duì)列,即先阻塞線程先訪問隊(duì)列。非公平性是對(duì)先等待的線程是非公平的,當(dāng)隊(duì)列可用時(shí),阻塞的線程都可以爭(zhēng)奪訪問隊(duì)列的資格,有可能先阻塞的線程最后才訪問隊(duì)列。初始化時(shí)有參數(shù)可以設(shè)置
是一個(gè)用鏈表實(shí)現(xiàn)的有界阻塞隊(duì)列。此隊(duì)列的默認(rèn)和最大長(zhǎng)度為Integer.MAX_VALUE。此隊(duì)列按照先進(jìn)先出的原則對(duì)元素進(jìn)行排序。
PriorityBlockingQueue是一個(gè)支持優(yōu)先級(jí)的無界阻塞隊(duì)列。默認(rèn)情況下元素采取自然順序升序排列。也可以自定義類實(shí)現(xiàn)compareTo()方法來指定元素排序規(guī)則,或者初始化PriorityBlockingQueue時(shí),指定構(gòu)造參數(shù)Comparator來對(duì)元素進(jìn)行排序。需要注意的是不能保證同優(yōu)先級(jí)元素的順序。
是一個(gè)支持延時(shí)獲取元素的無界阻塞隊(duì)列。隊(duì)列使用PriorityQueue來實(shí)現(xiàn)。隊(duì)列中的元素必須實(shí)現(xiàn)Delayed接口,在創(chuàng)建元素時(shí)可以指定多久才能從隊(duì)列中獲取當(dāng)前元素。只有在延遲期滿時(shí)才能從隊(duì)列中提取元素。
DelayQueue非常有用,可以將DelayQueue運(yùn)用在以下應(yīng)用場(chǎng)景。
緩存系統(tǒng)的設(shè)計(jì): 可以用DelayQueue保存緩存元素的有效期,使用一個(gè)線程循環(huán)查詢DelayQueue,一旦能從DelayQueue中獲取元素時(shí),表示緩存有效期到了。
是一個(gè)不存儲(chǔ)元素的阻塞隊(duì)列。每一個(gè)put操作必須等待一個(gè)take操作,否則不能繼續(xù)添加元素。SynchronousQueue可以看成是一個(gè)傳球手,負(fù)責(zé)把生產(chǎn)者線程處理的數(shù)據(jù)直接傳遞給消費(fèi)者線程。隊(duì)列本身并不存儲(chǔ)任何元素,非常適合傳遞性場(chǎng)景。SynchronousQueue的吞吐量高于LinkedBlockingQueue和ArrayBlockingQueue。
多了tryTransfer和transfer方法,
(1)transfer方法
如果當(dāng)前有消費(fèi)者正在等待接收元素(消費(fèi)者使用take()方法或帶時(shí)間限制的poll()方法時(shí)),transfer()可以把生產(chǎn)者傳入的元素立刻transfer(傳輸)給消費(fèi)者。如果沒有消費(fèi)者在等待接收元素,transfer()會(huì)將元素存放在隊(duì)列的tail節(jié)點(diǎn),并等到該元素被消費(fèi)者消費(fèi)了才返回。
(2)tryTransfer方法
tryTransfer()是用來試探生產(chǎn)者傳入的元素是否能直接傳給消費(fèi)者。如果沒有消費(fèi)者等待接收元素,則返回false。和transfer()的區(qū)別是,tryTransfer()無論消費(fèi)者是否接收,方法立即返回。而transfer()是必須等到消費(fèi)者消費(fèi)了才返回。
LinkedBlockingDeque是一個(gè)由鏈表結(jié)構(gòu)組成的雙向阻塞隊(duì)列。所謂雙向隊(duì)列指的是可以從隊(duì)列的兩端插入和移出元素。雙向隊(duì)列因?yàn)槎嗔艘粋€(gè)操作隊(duì)列的入口,在多線程同時(shí)入隊(duì)時(shí),也就減少了一半的競(jìng)爭(zhēng)。
多了addFirst、addLast、offerFirst、offerLast、peekFirst和peekLast等方法,以First單詞結(jié)尾的方法,表示插入、獲?。╬eek)或移除雙端隊(duì)列的第一個(gè)元素。以Last單詞結(jié)尾的方法,表示插入、獲取或移除雙端隊(duì)列的最后一個(gè)元素。另外,插入方法add等同于addLast,移除方法remove等效于removeFirst。但是take方法卻等同于takeFirst,不知道是不是JDK的bug,使用時(shí)還是用帶有First和Last后綴的方法更清楚。在初始化LinkedBlockingDeque時(shí)可以設(shè)置容量防止其過度膨脹。另外,雙向阻塞隊(duì)列可以運(yùn)用在“工作竊取”模式中。
Java中的線程池是運(yùn)用場(chǎng)景最多的并發(fā)框架,幾乎所有需要異步或并發(fā)執(zhí)行任務(wù)的程序都可以使用線程池。在開發(fā)過程中,合理地使用線程池能夠帶來3個(gè)好處。
第一:降低資源消耗。通過重復(fù)利用已創(chuàng)建的線程降低線程創(chuàng)建和銷毀造成的消耗。
第二:提高響應(yīng)速度。當(dāng)任務(wù)到達(dá)時(shí),任務(wù)可以不需要等到線程創(chuàng)建就能立即執(zhí)行。假設(shè)一個(gè)服務(wù)器完成一項(xiàng)任務(wù)所需時(shí)間為:T1 創(chuàng)建線程時(shí)間,T2 在線程中執(zhí)行任務(wù)的時(shí)間,T3 銷毀線程時(shí)間。 如果:T1 + T3 遠(yuǎn)大于 T2,則可以采用線程池,以提高服務(wù)器性能。線程池技術(shù)正是關(guān)注如何縮短或調(diào)整T1,T3時(shí)間的技術(shù),從而提高服務(wù)器程序性能的。它把T1,T3分別安排在服務(wù)器程序的啟動(dòng)和結(jié)束的時(shí)間段或者一些空閑的時(shí)間段,這樣在服務(wù)器程序處理客戶請(qǐng)求時(shí),不會(huì)有T1,T3的開銷了。
第三:提高線程的可管理性。線程是稀缺資源,如果無限制地創(chuàng)建,不僅會(huì)消耗系統(tǒng)資源,還會(huì)降低系統(tǒng)的穩(wěn)定性,使用線程池可以進(jìn)行統(tǒng)一分配、調(diào)優(yōu)和監(jiān)控。
Executor是一個(gè)接口,它是Executor框架的基礎(chǔ),它將任務(wù)的提交與任務(wù)的執(zhí)行分離開來;
線程池中的核心線程數(shù),當(dāng)提交一個(gè)任務(wù)時(shí),線程池創(chuàng)建一個(gè)新線程執(zhí)行任務(wù),直到當(dāng)前線程數(shù)等于corePoolSize;
如果當(dāng)前線程數(shù)為corePoolSize,繼續(xù)提交的任務(wù)被保存到阻塞隊(duì)列中,等待被執(zhí)行;
如果執(zhí)行了線程池的prestartAllCoreThreads()方法,線程池會(huì)提前創(chuàng)建并啟動(dòng)所有核心線程。
線程池中允許的最大線程數(shù)。如果當(dāng)前阻塞隊(duì)列滿了,且繼續(xù)提交任務(wù),則創(chuàng)建新的線程執(zhí)行任務(wù),前提是當(dāng)前線程數(shù)小于maximumPoolSize
線程空閑時(shí)的存活時(shí)間,即當(dāng)線程沒有任務(wù)執(zhí)行時(shí),繼續(xù)存活的時(shí)間。默認(rèn)情況下,該參數(shù)只在線程數(shù)大于corePoolSize時(shí)才有用
keepAliveTime的時(shí)間單位
workQueue必須是BlockingQueue阻塞隊(duì)列。當(dāng)線程池中的線程數(shù)超過它的corePoolSize的時(shí)候,線程會(huì)進(jìn)入阻塞隊(duì)列進(jìn)行阻塞等待。通過workQueue,線程池實(shí)現(xiàn)了阻塞功能。
一般來說,我們應(yīng)該盡量使用有界隊(duì)列,因?yàn)槭褂脽o界隊(duì)列作為工作隊(duì)列會(huì)對(duì)線程池帶來如下影響。
1)當(dāng)線程池中的線程數(shù)達(dá)到corePoolSize后,新任務(wù)將在無界隊(duì)列中等待,因此線程池中的線程數(shù)不會(huì)超過corePoolSize。
2)由于1,使用無界隊(duì)列時(shí)maximumPoolSize將是一個(gè)無效參數(shù)。
3)由于1和2,使用無界隊(duì)列時(shí)keepAliveTime將是一個(gè)無效參數(shù)。
4)更重要的,使用無界queue可能會(huì)耗盡系統(tǒng)資源,有界隊(duì)列則有助于防止資源耗盡,同時(shí)即使使用有界隊(duì)列,也要盡量控制隊(duì)列的大小在一個(gè)合適的范圍。
創(chuàng)建線程的工廠,通過自定義的線程工廠可以給每個(gè)新建的線程設(shè)置一個(gè)具有識(shí)別度的線程名,當(dāng)然還可以更加自由的對(duì)線程做更多的設(shè)置,比如設(shè)置所有的線程為守護(hù)線程。
Executors靜態(tài)工廠里默認(rèn)的threadFactory,線程的命名規(guī)則是“pool-數(shù)字-thread-數(shù)字”。
線程池的飽和策略,當(dāng)阻塞隊(duì)列滿了,且沒有空閑的工作線程,如果繼續(xù)提交任務(wù),必須采取一種策略處理該任務(wù),線程池提供了4種策略:
(1)AbortPolicy:直接拋出異常,默認(rèn)策略;
(2)CallerRunsPolicy:用調(diào)用者所在的線程來執(zhí)行任務(wù);
(3)DiscardOldestPolicy:丟棄阻塞隊(duì)列中靠最前的任務(wù),并執(zhí)行當(dāng)前任務(wù);
(4)DiscardPolicy:直接丟棄任務(wù);
當(dāng)然也可以根據(jù)應(yīng)用場(chǎng)景實(shí)現(xiàn)RejectedExecutionHandler接口,自定義飽和策略,如記錄日志或持久化存儲(chǔ)不能處理的任務(wù)。
1)如果當(dāng)前運(yùn)行的線程少于corePoolSize,則創(chuàng)建新線程來執(zhí)行任務(wù)(注意,執(zhí)行這一步驟需要獲取全局鎖)。
2)如果運(yùn)行的線程等于或多于corePoolSize,則將任務(wù)加入BlockingQueue。
3)如果無法將任務(wù)加入BlockingQueue(隊(duì)列已滿),則創(chuàng)建新的線程來處理任務(wù)。
4)如果創(chuàng)建新線程將使當(dāng)前運(yùn)行的線程超出maximumPoolSize,任務(wù)將被拒絕,并調(diào)用RejectedExecutionHandler.rejectedExecution()方法。
execute()方法用于提交不需要返回值的任務(wù),所以無法判斷任務(wù)是否被線程池執(zhí)行成功。
submit()方法用于提交需要返回值的任務(wù)。線程池會(huì)返回一個(gè)future類型的對(duì)象,通過這個(gè)future對(duì)象可以判斷任務(wù)是否執(zhí)行成功,并且可以通過future的get()方法來獲取返回值,get()方法會(huì)阻塞當(dāng)前線程直到任務(wù)完成,而使用get(long timeout,TimeUnit unit)方法則會(huì)阻塞當(dāng)前線程一段時(shí)間后立即返回,這時(shí)候有可能任務(wù)沒有執(zhí)行完。
可以通過調(diào)用線程池的shutdown或shutdownNow方法來關(guān)閉線程池。它們的原理是遍歷線程池中的工作線程,然后逐個(gè)調(diào)用線程的interrupt方法來中斷線程,所以無法響應(yīng)中斷的任務(wù)可能永遠(yuǎn)無法終止。但是它們存在一定的區(qū)別,shutdownNow首先將線程池的狀態(tài)設(shè)置成STOP,然后嘗試停止所有的正在執(zhí)行或暫停任務(wù)的線程,并返回等待執(zhí)行任務(wù)的列表,而shutdown只是將線程池的狀態(tài)設(shè)置成SHUTDOWN狀態(tài),然后中斷 所有沒有正在執(zhí)行任務(wù)的線程 。
只要調(diào)用了這兩個(gè)關(guān)閉方法中的任意一個(gè),isShutdown方法就會(huì)返回true。當(dāng)所有的任務(wù)都已關(guān)閉后,才表示線程池關(guān)閉成功,這時(shí)調(diào)用isTerminaed方法會(huì)返回true。至于應(yīng)該調(diào)用哪一種方法來關(guān)閉線程池,應(yīng)該由提交到線程池的任務(wù)特性決定,通常調(diào)用shutdown方法來關(guān)閉線程池,如果任務(wù)不一定要執(zhí)行完,則可以調(diào)用shutdownNow方法。
要想合理地配置線程池,就必須首先分析任務(wù)特性
要想合理地配置線程池,就必須首先分析任務(wù)特性,可以從以下幾個(gè)角度來分析。
性質(zhì)不同的任務(wù)可以用不同規(guī)模的線程池分開處理。
CPU密集型任務(wù)應(yīng)配置盡可能小的線程,如配置Ncpu+1個(gè)線程的線程池。由于IO密集型任務(wù)線程并不是一直在執(zhí)行任務(wù),則應(yīng)配置盡可能多的線程,如2*Ncpu。
混合型的任務(wù),如果可以拆分,將其拆分成一個(gè)CPU密集型任務(wù)和一個(gè)IO密集型任務(wù),只要這兩個(gè)任務(wù)執(zhí)行的時(shí)間相差不是太大,那么分解后執(zhí)行的吞吐量將高于串行執(zhí)行的吞吐量。如果這兩個(gè)任務(wù)執(zhí)行時(shí)間相差太大,則沒必要進(jìn)行分解??梢酝ㄟ^Runtime.getRuntime().availableProcessors()方法獲得當(dāng)前設(shè)備的CPU個(gè)數(shù)。
優(yōu)先級(jí)不同的任務(wù)可以使用優(yōu)先級(jí)隊(duì)列PriorityBlockingQueue來處理。它可以讓優(yōu)先級(jí)高的任務(wù)先執(zhí)行。
執(zhí)行時(shí)間不同的任務(wù)可以交給不同規(guī)模的線程池來處理,或者可以使用優(yōu)先級(jí)隊(duì)列,讓執(zhí)行時(shí)間短的任務(wù)先執(zhí)行。
建議使用有界隊(duì)列。有界隊(duì)列能增加系統(tǒng)的穩(wěn)定性和預(yù)警能力,可以根據(jù)需要設(shè)大一點(diǎn)兒,比如幾千。
如果當(dāng)時(shí)我們?cè)O(shè)置成無界隊(duì)列,那么線程池的隊(duì)列就會(huì)越來越多,有可能會(huì)撐滿內(nèi)存,導(dǎo)致整個(gè)系統(tǒng)不可用,而不只是后臺(tái)任務(wù)出現(xiàn)問題。
阻塞隊(duì)列常用于生產(chǎn)者和消費(fèi)者的場(chǎng)景,生產(chǎn)者就是往隊(duì)列中放入元素,消費(fèi)者就是從隊(duì)列中獲取元素,阻塞隊(duì)列就是生產(chǎn)者存放元素的容器,而消費(fèi)者也從該容器中拿元素。
阻塞隊(duì)列有兩種常見的阻塞場(chǎng)景,滿足這兩種阻塞場(chǎng)景的隊(duì)列就是阻塞隊(duì)列,分別如下:
Java中提供了7個(gè)阻塞隊(duì)列,分別如下:
ArrayBlockingQueue和LinkedBlockingQueue一般為常用的阻塞隊(duì)列。
接下來通過一個(gè)Demo演示阻塞隊(duì)列的用法。
這里維護(hù)了一個(gè)ArrayBlockingQueue,并指定其大小為10,創(chuàng)建了一個(gè)生產(chǎn)者線程和一個(gè)消費(fèi)者線程,生產(chǎn)者線程在生產(chǎn)5個(gè)事件后睡兩秒鐘,消費(fèi)者線程在消費(fèi)完“事件 - 5”后由于從隊(duì)列中拿不到元素,就會(huì)自動(dòng)阻塞,等待生產(chǎn)者往隊(duì)列中放入元素,只要隊(duì)列中有生產(chǎn)者放入元素,就會(huì)立即喚醒消費(fèi)者線程繼續(xù)獲取元素,詳見以下Log:
下面通過分析ArrayBlockingQueue的原理加深對(duì)阻塞隊(duì)列的理解。
在生產(chǎn)者消費(fèi)模型中,生產(chǎn)數(shù)據(jù)和消費(fèi)數(shù)據(jù)的速率不一致,如果生產(chǎn)數(shù)據(jù)速度快一些,消費(fèi)不過來,就會(huì)導(dǎo)致數(shù)據(jù)丟失,這時(shí)候我們就可以使用阻塞隊(duì)列來解決這個(gè)問題。
阻塞隊(duì)列是一個(gè)隊(duì)列,我們使用單線程生產(chǎn)數(shù)據(jù),使用多線程消費(fèi)數(shù)據(jù)。由于阻塞隊(duì)列的特點(diǎn):隊(duì)列為空的時(shí)候消費(fèi)者端阻塞,隊(duì)列滿的時(shí)候生產(chǎn)者端阻塞。多線程消費(fèi)數(shù)據(jù)起到了加速消費(fèi)的作用,使得生產(chǎn)的數(shù)據(jù)不會(huì)在隊(duì)列里積壓過多,而生產(chǎn)的數(shù)據(jù)也不會(huì)丟失處理。
首先通過接口類BlockingQueue中的注釋來簡(jiǎn)單了解阻塞隊(duì)列。
阻塞隊(duì)列是一個(gè)支持附加操作的特殊隊(duì)列:在隊(duì)列為空時(shí)回收元素會(huì)阻塞等待直到隊(duì)列非空,或在隊(duì)列已滿時(shí)插入元素,會(huì)阻塞等待直到隊(duì)列不滿。
阻塞隊(duì)列的方法提供了四種不同的處理方式:拋異常、返回特殊值(null或false)、阻塞當(dāng)前線程直到操作成功以及阻塞一段時(shí)間,超時(shí)退出。這四種處理方式分別對(duì)應(yīng)不同的函數(shù)接口:
是一個(gè)用數(shù)組實(shí)現(xiàn)的有界阻塞隊(duì)列,按先進(jìn)先出的原則對(duì)元素進(jìn)行排序。put和take方法分別為添加和刪除的阻塞方法。默認(rèn)情況下不保證線程公平。
ArrayBlockingQueue內(nèi)部使用一把重入鎖ReentrantLock來保證多個(gè)線程之間的插入刪除元素的同步;同時(shí)使用兩個(gè)條件對(duì)象Condition來實(shí)現(xiàn)阻塞邏輯,調(diào)用其await和signal方法來實(shí)現(xiàn)線程的等待和喚醒。
由于使用了ReentrantLock,所以ArrayBlockingQueue存在線程公平與不公平兩種選擇。
插入刪除元素的具體執(zhí)行邏輯: ArrayBlockingQueue
PS:這7個(gè)阻塞隊(duì)列本來想著一個(gè)一個(gè)解析的,但看了下源碼,邏輯其實(shí)沒有很復(fù)雜,所以后面幾個(gè)就只記一下內(nèi)部實(shí)現(xiàn)的主要點(diǎn)。
用鏈表實(shí)現(xiàn)的有界阻塞隊(duì)列,默認(rèn)和最大長(zhǎng)度為Integer.MAX_VALUE,隊(duì)列按照先進(jìn)先出的原則對(duì)元素排序。
插入元素在表尾,刪除元素在表頭。
LinkedBlockingQueue內(nèi)部使用了兩把重入鎖ReentrantLock,分別用來保護(hù)插入操作和刪除操作。
同樣也是使用兩個(gè)條件對(duì)象來實(shí)現(xiàn)阻塞邏輯。
支持優(yōu)先級(jí)的無界阻塞隊(duì)列,默認(rèn)按元素自然順序升序排列,可通過自定義類實(shí)現(xiàn)compareTo方法或指定構(gòu)造參數(shù)Comparator來指定元素排序規(guī)則,不保證同優(yōu)先級(jí)元素的順序。
PriorityBlockingQueue內(nèi)部使用的是數(shù)組對(duì)象來存儲(chǔ)元素,且數(shù)組容量初始化為11。
其內(nèi)部只使用了一把重入鎖ReentrantLock,和一個(gè)條件對(duì)象Condition,只用于阻塞和喚醒刪除元素操作的線程。
當(dāng)插入元素時(shí),若此時(shí)數(shù)組已滿,也不需要等待,它會(huì)嘗試擴(kuò)容,因此插入操作也不會(huì)有阻塞的可能。
PriorityBlockingQueue內(nèi)部還有一個(gè)allocationSpinLock自旋鎖,用于擴(kuò)容時(shí)的同步保護(hù),在執(zhí)行擴(kuò)容操作前,需先自旋嘗試將allocationSpinLock置為1,設(shè)置成功后才能繼續(xù)往下執(zhí)行。
一個(gè)不存儲(chǔ)元素的阻塞隊(duì)列,每一個(gè)put的線程會(huì)阻塞到直到有一個(gè)take線程取走元素為止,每一個(gè)take的線程會(huì)阻塞到直到有一個(gè)put的線程放入元素為止。
由于SynchronousQueue不存儲(chǔ)元素,所以類似peek操作或者迭代器操作都是無效的。
支持公平訪問隊(duì)列,默認(rèn)情況下線程采用非公平性策略訪問隊(duì)列。
SynchronousQueue只是一個(gè)對(duì)外的封裝層,其真正的實(shí)現(xiàn)邏輯在其類型為Transferer的成員變量transferer的transfer方法中;抽象類Transferer有兩個(gè)具體的實(shí)現(xiàn)類:TransferStack和TransferQueue,分別在非公平和公平的模式下使用。
Transferer類內(nèi)部是通過自旋鎖及CAS操作實(shí)現(xiàn)多個(gè)線程間的同步。
SynchronousQueue可當(dāng)做一個(gè)傳遞中介,負(fù)責(zé)將生產(chǎn)者線程處理的數(shù)據(jù)直接傳遞給消費(fèi)者線程,適用于傳遞性場(chǎng)景,吞吐量高。
其內(nèi)部的具體實(shí)現(xiàn)邏輯可參考: SynchronousQueue
LinkedTransferQueue內(nèi)部是通過自旋以及CAS操作來實(shí)現(xiàn)線程間的同步。
有鏈表結(jié)構(gòu)組成的雙向阻塞隊(duì)列,即可以從隊(duì)列的兩端插入或移除元素。
其內(nèi)部同樣擁有一把重入鎖ReentrantLock,兩個(gè)條件對(duì)象notEmpty和notFull。整體邏輯同LinkedBlockingQueue相似。
在初始化LinkedBlockingDeque時(shí)可以設(shè)置容量防止其過度膨脹,雙向阻塞隊(duì)列可以運(yùn)用在“工作竊取”模式中。