BlockingQueue
BlockingQueue接口實現(xiàn)Queue接口卿拴,它支持兩個附加操作:獲取元素時等待隊列變?yōu)榉强眨约按鎯υ貢r等待空間變得可用梨与。相對于同一操作他提供了四種機制:拋出異常堕花、返回特殊值、阻塞等待粥鞋、超時:
BlockingQueue常用于生產(chǎn)者和消費者場景缘挽。
JDK 8 中提供了七個阻塞隊列可供使用(上圖的DelayedWorkQueue是ScheduledThreadPoolExecutor的內(nèi)部類):
- ArrayBlockingQueue :一個由數(shù)組結(jié)構(gòu)組成的有界阻塞隊列。
- LinkedBlockingQueue :一個由鏈表結(jié)構(gòu)組成的無界阻塞隊列呻粹。
- PriorityBlockingQueue :一個支持優(yōu)先級排序的無界阻塞隊列壕曼。
- DelayQueue:一個使用優(yōu)先級隊列實現(xiàn)的無界阻塞隊列。
- SynchronousQueue:一個不存儲元素的阻塞隊列等浊。
- LinkedTransferQueue:一個由鏈表結(jié)構(gòu)組成的無界阻塞隊列腮郊。
- LinkedBlockingDeque:一個由鏈表結(jié)構(gòu)組成的雙向阻塞隊列。
ArrayBlockingQueue
基于數(shù)組的阻塞隊列筹燕,ArrayBlockingQueue內(nèi)部維護這一個定長數(shù)組轧飞,阻塞隊列的大小在初始化時就已經(jīng)確定了,其后無法更改撒踪。
采用可重入鎖ReentrantLock來保證線程安全性过咬,但是生產(chǎn)者和消費者是共用同一個鎖對象,這樣勢必會導致降低一定的吞吐量制妄。當然ArrayBlockingQueue完全可以采用分離鎖來實現(xiàn)生產(chǎn)者和消費者的并行操作掸绞,但是我認為這樣做只會給代碼帶來額外的復雜性,對于性能而言應該不會有太大的提升忍捡,因為基于數(shù)組的ArrayBlockingQueue在數(shù)據(jù)的寫入和讀取操作已經(jīng)非常輕巧了集漾。
ArrayBlockingQueue支持公平性和非公平性切黔,默認采用非公平模式,可以通過構(gòu)造函數(shù)設(shè)置為公平訪問策略(true)具篇。
PriorityBlockingQueue
PriorityBlockingQueue是支持優(yōu)先級的無界隊列纬霞。默認情況下采用自然順序排序,當然也可以通過自定義Comparator來指定元素的排序順序驱显。
PriorityBlockingQueue內(nèi)部采用二叉堆的實現(xiàn)方式诗芜,整個處理過程并不是特別復雜。添加操作則是不斷“上冒”埃疫,而刪除操作則是不斷“下掉”伏恐。
DelayQueue
DelayQueue是一個支持延時操作的無界阻塞隊列。列頭的元素是最先“到期”的元素栓霜,如果隊列里面沒有元素到期翠桦,是不能從列頭獲取元素的,哪怕有元素也不行胳蛮。也就是說只有在延遲期滿時才能夠從隊列中去元素销凑。
它主要運用于如下場景:
- 緩存系統(tǒng)的設(shè)計:緩存是有一定的時效性的,可以用DelayQueue保存緩存的有效期仅炊,然后利用一個線程查詢DelayQueue斗幼,如果取到元素就證明該緩存已經(jīng)失效了。
- 定時任務的調(diào)度:DelayQueue保存當天將要執(zhí)行的任務和執(zhí)行時間抚垄,一旦取到元素(任務)蜕窿,就執(zhí)行該任務。
DelayQueue采用支持優(yōu)先級的PriorityQueue來實現(xiàn)呆馁,但是隊列中的元素必須要實現(xiàn)Delayed接口桐经,Delayed接口用來標記那些應該在給定延遲時間之后執(zhí)行的對象,該接口提供了getDelay()方法返回元素節(jié)點的剩余時間智哀。同時次询,元素也必須要實現(xiàn)compareTo()方法,compareTo()方法需要提供與getDelay()方法一致的排序瓷叫。
SynchronousQueue
SynchronousQueue是一個神奇的隊列,他是一個不存儲元素的阻塞隊列送巡,也就是說他的每一個put操作都需要等待一個take操作摹菠,否則就不能繼續(xù)添加元素了,有點兒像Exchanger骗爆,類似于生產(chǎn)者和消費者進行交換次氨。
隊列本身不存儲任何元素,所以非常適用于傳遞性場景摘投,兩者直接進行對接煮寡。其吞吐量會高于ArrayBlockingQueue和LinkedBlockingQueue虹蓄。
SynchronousQueue支持公平和非公平的訪問策略,在默認情況下采用非公平性幸撕,也可以通過構(gòu)造函數(shù)來設(shè)置為公平性薇组。
SynchronousQueue的實現(xiàn)核心為Transferer接口,該接口有TransferQueue和TransferStack兩個實現(xiàn)類坐儿,分別對應著公平策略和非公平策略律胀。接口Transferer有一個tranfer()方法,該方法定義了轉(zhuǎn)移數(shù)據(jù)貌矿,如果e != null炭菌,相當于將一個數(shù)據(jù)交給消費者,如果e == null逛漫,則相當于從一個生產(chǎn)者接收一個消費者交出的數(shù)據(jù)黑低。
LinkedTransferQueue
LinkedTransferQueue是一個由鏈表組成的的無界阻塞隊列,該隊列是一個相當牛逼的隊列:它是ConcurrentLinkedQueue酌毡、SynchronousQueue (公平模式下)克握、無界的LinkedBlockingQueues等的超集。
與其他BlockingQueue相比阔馋,他多實現(xiàn)了一個接口TransferQueue玛荞,該接口是對BlockingQueue的一種補充,多了tryTranfer()和transfer()兩類方法:
- tranfer():若當前存在一個正在等待獲取的消費者線程呕寝,即立刻移交之勋眯。 否則,會插入當前元素e到隊列尾部下梢,并且等待進入阻塞狀態(tài)客蹋,到有消費者線程取走該元素
- tryTranfer(): 若當前存在一個正在等待獲取的消費者線程(使用take()或者poll()函數(shù)),使用該方法會即刻轉(zhuǎn)移/傳輸對象元素e孽江;若不存在讶坯,則返回false,并且不進入隊列岗屏。這是一個不阻塞的操作
LinkedBlockingDeque
LinkedBlockingDeque是一個有鏈表組成的雙向阻塞隊列辆琅,與前面的阻塞隊列相比它支持從兩端插入和移出元素。以first結(jié)尾的表示從對頭操作这刷,以last結(jié)尾的表示從對尾操作婉烟。
在初始化LinkedBlockingDeque時可以初始化隊列的容量,用來防止其再擴容時過渡膨脹暇屋。另外雙向阻塞隊列可以運用在“工作竊取”模式中似袁。
擴展閱讀
【死磕Java并發(fā)】—–J.U.C之阻塞隊列:ArrayBlockingQueue
【死磕Java并發(fā)】—–J.U.C之阻塞隊列:PriorityBlockingQueue
【死磕Java并發(fā)】—–J.U.C之阻塞隊列:DelayQueue
【死磕Java并發(fā)】—–J.U.C之阻塞隊列:SynchronousQueue
【死磕Java并發(fā)】—–J.U.C之阻塞隊列:LinkedTransferQueue
【死磕Java并發(fā)】—–J.U.C之阻塞隊列:LinkedBlockingDeque