并發(fā)容器之BlockingQueue

原創(chuàng)文章&經(jīng)驗(yàn)總結(jié)&從校招到A廠一路陽(yáng)光一路滄桑

詳情請(qǐng)戳www.codercc.com

image

1. BlockingQueue簡(jiǎn)介

在實(shí)際編程中髓废,會(huì)經(jīng)常使用到JDK中Collection集合框架中的各種容器類如實(shí)現(xiàn)List,Map,Queue接口的容器類舷嗡,但是這些容器類基本上不是線程安全的弛随,除了使用Collections可以將其轉(zhuǎn)換為線程安全的容器,Doug Lea大師為我們都準(zhǔn)備了對(duì)應(yīng)的線程安全的容器纫溃,如實(shí)現(xiàn)List接口的CopyOnWriteArrayList(關(guān)于CopyOnWriteArrayList可以看這篇文章)已球,實(shí)現(xiàn)Map接口的ConcurrentHashMap(關(guān)于ConcurrentHashMap可以看這篇文章)神凑,實(shí)現(xiàn)Queue接口的ConcurrentLinkedQueue(關(guān)于ConcurrentLinkedQueue可以看這篇文章)。

最常用的"生產(chǎn)者-消費(fèi)者"問(wèn)題中竿报,隊(duì)列通常被視作線程間操作的數(shù)據(jù)容器铅乡,這樣,可以對(duì)各個(gè)模塊的業(yè)務(wù)功能進(jìn)行解耦烈菌,生產(chǎn)者將“生產(chǎn)”出來(lái)的數(shù)據(jù)放置在數(shù)據(jù)容器中阵幸,而消費(fèi)者僅僅只需要在“數(shù)據(jù)容器”中進(jìn)行獲取數(shù)據(jù)即可,這樣生產(chǎn)者線程和消費(fèi)者線程就能夠進(jìn)行解耦芽世,只專注于自己的業(yè)務(wù)功能即可挚赊。阻塞隊(duì)列(BlockingQueue)被廣泛使用在“生產(chǎn)者-消費(fèi)者”問(wèn)題中,其原因是BlockingQueue提供了可阻塞的插入和移除的方法济瓢。當(dāng)隊(duì)列容器已滿咬腕,生產(chǎn)者線程會(huì)被阻塞,直到隊(duì)列未滿葬荷;當(dāng)隊(duì)列容器為空時(shí)涨共,消費(fèi)者線程會(huì)被阻塞,直至隊(duì)列非空時(shí)為止宠漩。

2. 基本操作

BlockingQueue基本操作總結(jié)如下(此圖來(lái)源于JAVA API文檔):

BlockingQueue基本操作.png

BlockingQueue繼承于Queue接口举反,因此,對(duì)數(shù)據(jù)元素的基本操作有:

插入元素

  1. add(E e) :往隊(duì)列插入數(shù)據(jù)扒吁,當(dāng)隊(duì)列滿時(shí)火鼻,插入元素時(shí)會(huì)拋出IllegalStateException異常;
  2. offer(E e):當(dāng)往隊(duì)列插入數(shù)據(jù)時(shí)雕崩,插入成功返回true魁索,否則則返回false。當(dāng)隊(duì)列滿時(shí)不會(huì)拋出異常盼铁;

刪除元素

  1. remove(Object o):從隊(duì)列中刪除數(shù)據(jù)粗蔚,成功則返回true,否則為false
  2. poll:刪除數(shù)據(jù)饶火,當(dāng)隊(duì)列為空時(shí)鹏控,返回null致扯;

查看元素

  1. element:獲取隊(duì)頭元素,如果隊(duì)列為空時(shí)則拋出NoSuchElementException異常当辐;
  2. peek:獲取隊(duì)頭元素抖僵,如果隊(duì)列為空則拋出NoSuchElementException異常

BlockingQueue具有的特殊操作:

插入數(shù)據(jù):

  1. put:當(dāng)阻塞隊(duì)列容量已經(jīng)滿時(shí),往阻塞隊(duì)列插入數(shù)據(jù)的線程會(huì)被阻塞缘揪,直至阻塞隊(duì)列已經(jīng)有空余的容量可供使用耍群;
  2. offer(E e, long timeout, TimeUnit unit):若阻塞隊(duì)列已經(jīng)滿時(shí),同樣會(huì)阻塞插入數(shù)據(jù)的線程找筝,直至阻塞隊(duì)列已經(jīng)有空余的地方世吨,與put方法不同的是,該方法會(huì)有一個(gè)超時(shí)時(shí)間呻征,若超過(guò)當(dāng)前給定的超時(shí)時(shí)間耘婚,插入數(shù)據(jù)的線程會(huì)退出;

刪除數(shù)據(jù)

  1. take():當(dāng)阻塞隊(duì)列為空時(shí)陆赋,獲取隊(duì)頭數(shù)據(jù)的線程會(huì)被阻塞沐祷;
  2. poll(long timeout, TimeUnit unit):當(dāng)阻塞隊(duì)列為空時(shí),獲取數(shù)據(jù)的線程會(huì)被阻塞攒岛,另外赖临,如果被阻塞的線程超過(guò)了給定的時(shí)長(zhǎng),該線程會(huì)退出

3. 常用的BlockingQueue

實(shí)現(xiàn)BlockingQueue接口的有ArrayBlockingQueue, DelayQueue, LinkedBlockingDeque, LinkedBlockingQueue, LinkedTransferQueue, PriorityBlockingQueue, SynchronousQueue灾锯,而這幾種常見(jiàn)的阻塞隊(duì)列也是在實(shí)際編程中會(huì)常用的兢榨,下面對(duì)這幾種常見(jiàn)的阻塞隊(duì)列進(jìn)行說(shuō)明:

1.ArrayBlockingQueue

ArrayBlockingQueue是由數(shù)組實(shí)現(xiàn)的有界阻塞隊(duì)列。該隊(duì)列命令元素FIFO(先進(jìn)先出)顺饮。因此吵聪,對(duì)頭元素時(shí)隊(duì)列中存在時(shí)間最長(zhǎng)的數(shù)據(jù)元素,而對(duì)尾數(shù)據(jù)則是當(dāng)前隊(duì)列最新的數(shù)據(jù)元素兼雄。ArrayBlockingQueue可作為“有界數(shù)據(jù)緩沖區(qū)”吟逝,生產(chǎn)者插入數(shù)據(jù)到隊(duì)列容器中,并由消費(fèi)者提取赦肋。ArrayBlockingQueue一旦創(chuàng)建块攒,容量不能改變。

當(dāng)隊(duì)列容量滿時(shí)佃乘,嘗試將元素放入隊(duì)列將導(dǎo)致操作阻塞;嘗試從一個(gè)空隊(duì)列中取一個(gè)元素也會(huì)同樣阻塞囱井。

ArrayBlockingQueue默認(rèn)情況下不能保證線程訪問(wèn)隊(duì)列的公平性,所謂公平性是指嚴(yán)格按照線程等待的絕對(duì)時(shí)間順序趣避,即最先等待的線程能夠最先訪問(wèn)到ArrayBlockingQueue庞呕。而非公平性則是指訪問(wèn)ArrayBlockingQueue的順序不是遵守嚴(yán)格的時(shí)間順序,有可能存在鹅巍,一旦ArrayBlockingQueue可以被訪問(wèn)時(shí)千扶,長(zhǎng)時(shí)間阻塞的線程依然無(wú)法訪問(wèn)到ArrayBlockingQueue。如果保證公平性骆捧,通常會(huì)降低吞吐量澎羞。如果需要獲得公平性的ArrayBlockingQueue,可采用如下代碼:

private static ArrayBlockingQueue<Integer> blockingQueue = new ArrayBlockingQueue<Integer>(10,true);

關(guān)于ArrayBlockingQueue的實(shí)現(xiàn)原理敛苇,可以看這篇文章妆绞。

2.LinkedBlockingQueue

LinkedBlockingQueue是用鏈表實(shí)現(xiàn)的有界阻塞隊(duì)列,同樣滿足FIFO的特性枫攀,與ArrayBlockingQueue相比起來(lái)具有更高的吞吐量括饶,為了防止LinkedBlockingQueue容量迅速增,損耗大量?jī)?nèi)存来涨。通常在創(chuàng)建LinkedBlockingQueue對(duì)象時(shí)图焰,會(huì)指定其大小,如果未指定蹦掐,容量等于Integer.MAX_VALUE

3.PriorityBlockingQueue

PriorityBlockingQueue是一個(gè)支持優(yōu)先級(jí)的無(wú)界阻塞隊(duì)列技羔。默認(rèn)情況下元素采用自然順序進(jìn)行排序,也可以通過(guò)自定義類實(shí)現(xiàn)compareTo()方法來(lái)指定元素排序規(guī)則卧抗,或者初始化時(shí)通過(guò)構(gòu)造器參數(shù)Comparator來(lái)指定排序規(guī)則藤滥。

4.SynchronousQueue

SynchronousQueue每個(gè)插入操作必須等待另一個(gè)線程進(jìn)行相應(yīng)的刪除操作,因此社裆,SynchronousQueue實(shí)際上沒(méi)有存儲(chǔ)任何數(shù)據(jù)元素拙绊,因?yàn)橹挥芯€程在刪除數(shù)據(jù)時(shí),其他線程才能插入數(shù)據(jù)泳秀,同樣的标沪,如果當(dāng)前有線程在插入數(shù)據(jù)時(shí),線程才能刪除數(shù)據(jù)嗜傅。SynchronousQueue也可以通過(guò)構(gòu)造器參數(shù)來(lái)為其指定公平性谨娜。

5.LinkedTransferQueue

LinkedTransferQueue是一個(gè)由鏈表數(shù)據(jù)結(jié)構(gòu)構(gòu)成的無(wú)界阻塞隊(duì)列,由于該隊(duì)列實(shí)現(xiàn)了TransferQueue接口磺陡,與其他阻塞隊(duì)列相比主要有以下不同的方法:

transfer(E e)
如果當(dāng)前有線程(消費(fèi)者)正在調(diào)用take()方法或者可延時(shí)的poll()方法進(jìn)行消費(fèi)數(shù)據(jù)時(shí)趴梢,生產(chǎn)者線程可以調(diào)用transfer方法將數(shù)據(jù)傳遞給消費(fèi)者線程。如果當(dāng)前沒(méi)有消費(fèi)者線程的話币他,生產(chǎn)者線程就會(huì)將數(shù)據(jù)插入到隊(duì)尾坞靶,直到有消費(fèi)者能夠進(jìn)行消費(fèi)才能退出;

tryTransfer(E e)
tryTransfer方法如果當(dāng)前有消費(fèi)者線程(調(diào)用take方法或者具有超時(shí)特性的poll方法)正在消費(fèi)數(shù)據(jù)的話蝴悉,該方法可以將數(shù)據(jù)立即傳送給消費(fèi)者線程彰阴,如果當(dāng)前沒(méi)有消費(fèi)者線程消費(fèi)數(shù)據(jù)的話,就立即返回false拍冠。因此尿这,與transfer方法相比簇抵,transfer方法是必須等到有消費(fèi)者線程消費(fèi)數(shù)據(jù)時(shí),生產(chǎn)者線程才能夠返回射众。而tryTransfer方法能夠立即返回結(jié)果退出碟摆。

tryTransfer(E e,long timeout,imeUnit unit)</br>
與transfer基本功能一樣,只是增加了超時(shí)特性叨橱,如果數(shù)據(jù)才規(guī)定的超時(shí)時(shí)間內(nèi)沒(méi)有消費(fèi)者進(jìn)行消費(fèi)的話典蜕,就返回false

6.LinkedBlockingDeque

LinkedBlockingDeque是基于鏈表數(shù)據(jù)結(jié)構(gòu)的有界阻塞雙端隊(duì)列罗洗,如果在創(chuàng)建對(duì)象時(shí)為指定大小時(shí)愉舔,其默認(rèn)大小為Integer.MAX_VALUE。與LinkedBlockingQueue相比伙菜,主要的不同點(diǎn)在于轩缤,LinkedBlockingDeque具有雙端隊(duì)列的特性。LinkedBlockingDeque基本操作如下圖所示(來(lái)源于java文檔)


LinkedBlockingDeque的基本操作.png

如上圖所示贩绕,LinkedBlockingDeque的基本操作可以分為四種類型:1.特殊情況典奉,拋出異常;2.特殊情況丧叽,返回特殊值如null或者false卫玖;3.當(dāng)線程不滿足操作條件時(shí),線程會(huì)被阻塞直至條件滿足踊淳;4. 操作具有超時(shí)特性假瞬。

另外,LinkedBlockingDeque實(shí)現(xiàn)了BlockingDueue接口而LinkedBlockingQueue實(shí)現(xiàn)的是BlockingQueue迂尝,這兩個(gè)接口的主要區(qū)別如下圖所示(來(lái)源于java文檔):


BlockingQueue和BlockingDeque的區(qū)別.png

從上圖可以看出脱茉,兩個(gè)接口的功能是可以等價(jià)使用的,比如BlockingQueue的add方法和BlockingDeque的addLast方法的功能是一樣的垄开。

7.DelayQueue

DelayQueue是一個(gè)存放實(shí)現(xiàn)Delayed接口的數(shù)據(jù)的無(wú)界阻塞隊(duì)列琴许,只有當(dāng)數(shù)據(jù)對(duì)象的延時(shí)時(shí)間達(dá)到時(shí)才能插入到隊(duì)列進(jìn)行存儲(chǔ)。如果當(dāng)前所有的數(shù)據(jù)都還沒(méi)有達(dá)到創(chuàng)建時(shí)所指定的延時(shí)期溉躲,則隊(duì)列沒(méi)有隊(duì)頭榜田,并且線程通過(guò)poll等方法獲取數(shù)據(jù)元素則返回null。所謂數(shù)據(jù)延時(shí)期滿時(shí)锻梳,則是通過(guò)Delayed接口的getDelay(TimeUnit.NANOSECONDS)來(lái)進(jìn)行判定箭券,如果該方法返回的是小于等于0則說(shuō)明該數(shù)據(jù)元素的延時(shí)期已滿。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末疑枯,一起剝皮案震驚了整個(gè)濱河市辩块,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖废亭,帶你破解...
    沈念sama閱讀 206,311評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件国章,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡豆村,警方通過(guò)查閱死者的電腦和手機(jī)液兽,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)你画,“玉大人抵碟,你說(shuō)我怎么就攤上這事桃漾』捣耍” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,671評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵撬统,是天一觀的道長(zhǎng)适滓。 經(jīng)常有香客問(wèn)我,道長(zhǎng)恋追,這世上最難降的妖魔是什么凭迹? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,252評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮苦囱,結(jié)果婚禮上嗅绸,老公的妹妹穿的比我還像新娘。我一直安慰自己撕彤,他們只是感情好鱼鸠,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著羹铅,像睡著了一般蚀狰。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上职员,一...
    開(kāi)封第一講書(shū)人閱讀 49,031評(píng)論 1 285
  • 那天麻蹋,我揣著相機(jī)與錄音,去河邊找鬼焊切。 笑死扮授,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的专肪。 我是一名探鬼主播糙箍,決...
    沈念sama閱讀 38,340評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼牵祟!你這毒婦竟也來(lái)了深夯?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 36,973評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎咕晋,沒(méi)想到半個(gè)月后雹拄,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,466評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡掌呜,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評(píng)論 2 323
  • 正文 我和宋清朗相戀三年滓玖,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片质蕉。...
    茶點(diǎn)故事閱讀 38,039評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡势篡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出模暗,到底是詐尸還是另有隱情禁悠,我是刑警寧澤,帶...
    沈念sama閱讀 33,701評(píng)論 4 323
  • 正文 年R本政府宣布兑宇,位于F島的核電站碍侦,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏隶糕。R本人自食惡果不足惜瓷产,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望枚驻。 院中可真熱鬧濒旦,春花似錦、人聲如沸再登。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,259評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)霎冯。三九已至铃拇,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間沈撞,已是汗流浹背慷荔。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留缠俺,地道東北人显晶。 一個(gè)月前我還...
    沈念sama閱讀 45,497評(píng)論 2 354
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像壹士,于是被迫代替她去往敵國(guó)和親磷雇。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評(píng)論 2 345