java并發(fā)編程工具類JUC第一篇:BlockingQueue阻塞隊列

Java BlockingQueue接口java.util.concurrent.BlockingQueue表示一個可以存取元素语淘,并且線程安全的隊列侥猩。換句話說籽前,當(dāng)多線程同時從 JavaBlockingQueue中插入元素种冬、獲取元素的時候蛙婴,不會導(dǎo)致任何并發(fā)問題(元素被插入多次粗井、處理多次等問題)。

從java BlockingQueue可以引申出一個概念:阻塞隊列街图,是指隊列本身可以阻塞線程向隊列里面插入元素浇衬,或者阻塞線程從隊列里面獲取元素。比如:當(dāng)一個線程嘗試去從一個空隊列里面獲取元素的時候餐济,這個線程將被阻塞直到隊列內(nèi)元素數(shù)量不再為空耘擂。當(dāng)然,線程是否會被阻塞取決于你調(diào)用什么方法從BlockingQueue獲取元素絮姆,有的方法會阻塞線程醉冤,有的方法會拋出異常等等,下文我們會詳細(xì)介紹篙悯。

一蚁阳、BlockingQueue 接口實現(xiàn)類

本文不會去介紹如何自己實現(xiàn)BlockingQueue接口,JUC已經(jīng)為我們做好了相關(guān)的一些接口實現(xiàn)類鸽照。
BlockingQueue是一個java接口韵吨,當(dāng)我們需要使用阻塞隊列的時候,可以使用它的實現(xiàn)類移宅。java.util.concurrent包里面有如下的一些實現(xiàn)類實現(xiàn)了BlockingQueue接口。

  • ArrayBlockingQueue
  • DelayQueue
  • LinkedBlockingQueue
  • LinkedBlockingDeque
  • LinkedTransferQueue
  • PriorityBlockingQueue
  • SynchronousQueue

在本文以及后續(xù)的文章中椿疗,會依次為大家介紹這些實現(xiàn)類的作用及使用場景漏峰,期待您的關(guān)注。

二届榄、BlockingQueue 應(yīng)用場景介紹

BlockingQueue通常被應(yīng)用在一個線程生產(chǎn)對象放入隊列浅乔,與此同時另一個線程消費隊列內(nèi)的對象的場景下。下面的這張圖說明了使用場景:

生產(chǎn)者線程不斷的生產(chǎn)新的對象,并將他們插入到BlockingQueue靖苇,直到隊列中object的數(shù)量達(dá)到隊列存儲容量的上限席噩。也就是說當(dāng)隊列中對象達(dá)到容量上限的時候,生產(chǎn)者線程將被阻塞贤壁,不能再向隊列中插入新的對象悼枢。生產(chǎn)者線程將保持阻塞等待狀態(tài),直到消費者線程從隊列中拿走Object脾拆,讓隊列有空余位置放入新的對象馒索。

消費者線程不斷的從BlockingQueue取出對象并將其進(jìn)行處理。如果消費者線程嘗試從一個空隊列中獲取一個對象名船,消費者線程將被阻塞處于等待狀態(tài)绰上,直到生產(chǎn)者向隊列中放入一個新的對象。

所以BlockingQueue經(jīng)常被用于生產(chǎn)消費的緩沖隊列渠驼,如果你不想用分布式的或者中間件消息隊列(redis蜈块、kafka)等(因為對于一個小功能會增加比較大的獨立中間件運維成本),BlockingQueue可以能是一個備選的選項迷扇。

2.1.BlockingQueue 方法介紹

JavaBlockingQueue 提供了四組不同的方法用于向隊列中插入百揭、移除、檢查隊列中包含某一元素對象谋梭。每一組方法在被調(diào)用之后的響應(yīng)行為上有所不同信峻,如下:

拋出異常 返回特定值 阻塞后一直等待 阻塞后等待超時
插入對象 add(o) offer(o) put(o) offer(o, timeout, timeunit)
移除對象 remove(o) poll() take() poll(timeout, timeunit)
檢查對象存在 element() peek()

上面的方法的四種行為分別的含義是

  1. 拋出異常: 如果調(diào)用方法后不能立即響應(yīng)結(jié)果(空隊列或滿隊列),則拋出異常瓮床。
  2. 返回特定值: 如果調(diào)用方法后不能立即響應(yīng)結(jié)果(空隊列或滿隊列)盹舞,則返回特定的值(通常是true/false),true表示方法執(zhí)行成功隘庄,否則表示方法執(zhí)行失敗踢步。
  3. 阻塞后一直等待: 如果調(diào)用方法后不能立即響應(yīng)結(jié)果(空隊列或滿隊列),該方法將被阻塞一直處于等待狀態(tài)丑掺。
  4. 阻塞后等待超時: 如果調(diào)用方法后不能立即響應(yīng)結(jié)果(空隊列或滿隊列)获印,該方法將在一定時間范圍內(nèi)被阻塞等待,也就是在超時時間范圍內(nèi)阻塞街州。當(dāng)超出超時時間之后兼丰,方法線程將不再阻塞,而是返回一個特定的值(通常是true/false)唆缴,true表示方法執(zhí)行成功鳍征,否則表示方法執(zhí)行失敗。

另外面徽,BlockingQueue隊列不允許向其內(nèi)部插入null艳丛,如果你向隊列中插入null匣掸,將會引發(fā)NullPointerException異常。
一般的隊列都是從隊首放入對象氮双,從隊尾獲取對象,BlockingQueue不僅支持從隊首隊尾操作數(shù)據(jù)對象碰酝,還支持從隊列中其他任何位置操作數(shù)據(jù)。比如:你已經(jīng)向隊列中放入一個對象并等待處理戴差,但是出于某些特殊原因希望將這個對象從隊列中刪除掉送爸。你可以調(diào)用remove(o)方法來刪除隊列中的一個特定的o對象。當(dāng)然我們的程序不能經(jīng)常性的這樣做造挽,因為隊列這種數(shù)據(jù)結(jié)構(gòu)經(jīng)常從中間位置操作數(shù)據(jù)的效率是極低的碱璃,所以除非必要不建議這樣做。

add(o)

BlockingQueueadd() 方法可以將o對象以參數(shù)的形式插入到隊列里面饭入,如果隊列里面有剩余空間嵌器,將被立即插入;如果隊列里面沒有剩余空間谐丢,add()方法將跑出 IllegalStateException.

offer(o)

BlockingQueueoffer() 方法可以將o對象以參數(shù)的形式插入到隊列里面爽航,如果隊列里面有剩余空間,將被立即插入乾忱;如果隊列里面沒有剩余空間讥珍,offer()方法將返回特定的值false.

offer(o, long millis, TimeUnit timeUnit)

BlockingQueueoffer() 方法有另外一個版本的實現(xiàn),存在超時時間的設(shè)置參數(shù)窄瘟。這個版本的offer()方法將o對象以參數(shù)的形式插入到隊列里面衷佃,如果隊列里面有剩余空間,將被立即插入蹄葱;如果隊列里面沒有剩余空間氏义,調(diào)用offer方法的線程在超時時間內(nèi)將被阻塞處于等到狀態(tài),當(dāng)阻塞時間大于超時時間之后图云,隊列內(nèi)如果仍然沒有剩余空間放入新對象惯悠,offer()方法將返回false.

put(o)

BlockingQueueput() 方法可以將o對象以參數(shù)的形式插入到隊列里面,如果隊列里面有剩余空間竣况,將被立即插入克婶;如果隊列里面沒有剩余空間,調(diào)用put的方法的線程將被阻塞丹泉,直到BlockingQueue里面騰出新的空間可以放入對象為止情萤。

take()

BlockingQueuetake() 方法取出并移除隊列中的第一個元素(對象),如果BlockingQueue隊列中不包含任何的元素摹恨,調(diào)用take()方法的線程將被阻塞筋岛,直到有新的元素對象插入到隊列中為止。

poll()

BlockingQueuepoll() 方法取出并移除隊列中的第一個元素(對象)睬塌,如果BlockingQueue隊列中不包含任何的元素,poll()方法將返回null.

poll(long timeMillis, TimeUnit timeUnit)

BlockingQueuepoll(long timeMillis, TimeUnit timeUnit)方法同樣存在一個超時時間限制的版本,正常情況下該方法取出并移除隊列中的第一個元素(對象)揩晴。如果BlockingQueue隊列中不包含任何的元素勋陪,在超時時間范圍內(nèi),如果仍然沒有新的對象放入隊列硫兰,這個版本的poll()方法將被阻塞處于等待狀態(tài)诅愚;當(dāng)阻塞時間大于超時時間之后,poll(long timeMillis, TimeUnit timeUnit)返回null

remove(Object o)

BlockingQueueremove(Object o) 方法可以從隊列中刪除一個以參數(shù)形式給定的元素對象劫映,remove()方法使用o.equals(element)將傳入?yún)?shù)o與隊列中的對象進(jìn)行一一比對违孝,從而判定要刪除的對象是否在隊列中存在,如果存在就從隊列中刪除并返回true泳赋,否則返回false雌桑。

需要注意的是:如果隊列中有多個與傳入?yún)?shù)equals相等的對象,只刪除其中一個祖今,不會將隊列中所有匹配的對象都刪除校坑。

peek()

BlockingQueuepeek() 方法將取出隊列中的第一個元素對象,但是并不會將其從隊列中刪除千诬。如果隊列中目前沒有任何的元素耍目,也就是空隊列,peek()方法將返回null.

element()

BlockingQueueelement()方法將取出隊列中的第一個元素對象徐绑,但是并不會將其從隊列中刪除邪驮。如果隊列中目前沒有任何的元素,也就是空隊列傲茄,element()方法將拋出 NoSuchElementException.

contains(Object o)

BlockingQueuecontains(Object o) 方法用來判斷當(dāng)前隊列中是否存在某個對象毅访,該對象與傳入?yún)?shù)o相等(Objects.equals(o, element)被用來判定對象的相等性)。遍歷隊列中的所有元素烫幕,一旦在隊列中發(fā)現(xiàn)匹配的元素對象俺抽,該方法將返回true;如果沒有任何的元素匹配相等较曼,該方法返回false磷斧。

drainTo(Collection dest)

drainTo(Collection dest)方法一次性的將隊列中的所有元素取出到集合類Collection dest對象中保存。

drainTo(Collection dest, int maxElements)

drainTo(Collection dest)方法一次性的從隊列中取出maxElements個元素到集合類Collection dest對象中保存捷犹。

size()

BlockingQueuesize() 方法返回隊列中目前共有多少個元素

remainingCapacity()

BlockingQueueremainingCapacity() 方法將返回隊列目前還剩多少個可用空間用于放入新的對象弛饭。剩余空間容量=隊列的總?cè)萘?已經(jīng)被占用的空間數(shù)量

歡迎關(guān)注我的博客,里面有很多精品合集

  • 本文轉(zhuǎn)載注明出處(必須帶連接萍歉,不能只轉(zhuǎn)文字):字母哥博客侣颂。

覺得對您有幫助的話,幫我點贊枪孩、分享憔晒!您的支持是我不竭的創(chuàng)作動力藻肄! 。另外拒担,筆者最近一段時間輸出了如下的精品內(nèi)容嘹屯,期待您的關(guān)注。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末从撼,一起剝皮案震驚了整個濱河市州弟,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌低零,老刑警劉巖婆翔,帶你破解...
    沈念sama閱讀 217,084評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異掏婶,居然都是意外死亡啃奴,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,623評論 3 392
  • 文/潘曉璐 我一進(jìn)店門气堕,熙熙樓的掌柜王于貴愁眉苦臉地迎上來纺腊,“玉大人,你說我怎么就攤上這事茎芭∫灸ぃ” “怎么了?”我有些...
    開封第一講書人閱讀 163,450評論 0 353
  • 文/不壞的土叔 我叫張陵梅桩,是天一觀的道長壹粟。 經(jīng)常有香客問我,道長宿百,這世上最難降的妖魔是什么趁仙? 我笑而不...
    開封第一講書人閱讀 58,322評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮垦页,結(jié)果婚禮上雀费,老公的妹妹穿的比我還像新娘。我一直安慰自己痊焊,他們只是感情好盏袄,可當(dāng)我...
    茶點故事閱讀 67,370評論 6 390
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著薄啥,像睡著了一般辕羽。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上垄惧,一...
    開封第一講書人閱讀 51,274評論 1 300
  • 那天刁愿,我揣著相機(jī)與錄音,去河邊找鬼到逊。 笑死铣口,一個胖子當(dāng)著我的面吹牛滤钱,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播脑题,決...
    沈念sama閱讀 40,126評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼菩暗,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了旭蠕?” 一聲冷哼從身側(cè)響起旷坦,我...
    開封第一講書人閱讀 38,980評論 0 275
  • 序言:老撾萬榮一對情侶失蹤掏熬,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后秒梅,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體旗芬,經(jīng)...
    沈念sama閱讀 45,414評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,599評論 3 334
  • 正文 我和宋清朗相戀三年捆蜀,在試婚紗的時候發(fā)現(xiàn)自己被綠了疮丛。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,773評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡辆它,死狀恐怖誊薄,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情锰茉,我是刑警寧澤呢蔫,帶...
    沈念sama閱讀 35,470評論 5 344
  • 正文 年R本政府宣布,位于F島的核電站飒筑,受9級特大地震影響片吊,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜协屡,卻給世界環(huán)境...
    茶點故事閱讀 41,080評論 3 327
  • 文/蒙蒙 一俏脊、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧肤晓,春花似錦爷贫、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,713評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至余蟹,卻和暖如春卷胯,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背威酒。 一陣腳步聲響...
    開封第一講書人閱讀 32,852評論 1 269
  • 我被黑心中介騙來泰國打工窑睁, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留挺峡,地道東北人。 一個月前我還...
    沈念sama閱讀 47,865評論 2 370
  • 正文 我出身青樓担钮,卻偏偏與公主長得像橱赠,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子箫津,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,689評論 2 354

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