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() |
上面的方法的四種行為分別的含義是
- 拋出異常: 如果調(diào)用方法后不能立即響應(yīng)結(jié)果(空隊列或滿隊列),則拋出異常瓮床。
- 返回特定值: 如果調(diào)用方法后不能立即響應(yīng)結(jié)果(空隊列或滿隊列)盹舞,則返回特定的值(通常是true/false),true表示方法執(zhí)行成功隘庄,否則表示方法執(zhí)行失敗踢步。
- 阻塞后一直等待: 如果調(diào)用方法后不能立即響應(yīng)結(jié)果(空隊列或滿隊列),該方法將被阻塞一直處于等待狀態(tài)丑掺。
- 阻塞后等待超時: 如果調(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)注。