Java BlockingQueue介面java.util.concurrent.BlockingQueue
表示一個可以存取元素,並且執行緒安全的佇列。換句話說,當多執行緒同時從 JavaBlockingQueue
中插入元素、獲取元素的時候,不會導致任何併發問題(元素被插入多次、處理多次等問題)。
從java BlockingQueue
可以引申出一個概念:阻塞佇列,是指佇列本身可以阻塞執行緒向佇列裡面插入元素,或者阻塞執行緒從佇列裡面獲取元素。比如:當一個執行緒嘗試去從一個空佇列裡面獲取元素的時候,這個執行緒將被阻塞直到佇列內元素數量不再為空。當然,執行緒是否會被阻塞取決於你呼叫什麼方法從BlockingQueue
獲取元素,有的方法會阻塞執行緒,有的方法會丟擲異常等等,下文我們會詳細介紹。
一、BlockingQueue 介面實現類
本文不會去介紹如何自己實現BlockingQueue
介面,JUC已經為我們做好了相關的一些介面實現類。
BlockingQueue
是一個java介面,當我們需要使用阻塞佇列的時候,可以使用它的實現類。java.util.concurrent
包裡面有如下的一些實現類實現了BlockingQueue
介面。
- ArrayBlockingQueue
- DelayQueue
- LinkedBlockingQueue
- LinkedBlockingDeque
- LinkedTransferQueue
- PriorityBlockingQueue
- SynchronousQueue
在本文以及後續的文章中,會依次為大家介紹這些實現類的作用及使用場景,期待您的關注。
二、BlockingQueue 應用場景介紹
BlockingQueue
通常被應用在一個執行緒生產物件放入佇列,與此同時另一個執行緒消費佇列內的物件的場景下。下面的這張圖說明了使用場景:
生產者執行緒不斷的生產新的物件,並將他們插入到BlockingQueue
,直到佇列中object的數量達到佇列儲存容量的上限。也就是說當佇列中物件達到容量上限的時候,生產者執行緒將被阻塞,不能再向佇列中插入新的物件。生產者執行緒將保持阻塞等待狀態,直到消費者執行緒從佇列中拿走Object,讓佇列有空餘位置放入新的物件。
消費者執行緒不斷的從BlockingQueue
取出物件並將其進行處理。如果消費者執行緒嘗試從一個空佇列中獲取一個物件,消費者執行緒將被阻塞處於等待狀態,直到生產者向佇列中放入一個新的物件。
所以BlockingQueue經常被用於生產消費的緩衝佇列,如果你不想用分散式的或者中介軟體訊息佇列(redis、kafka)等(因為對於一個小功能會增加比較大的獨立中介軟體運維成本),BlockingQueue可以能是一個備選的選項。
2.1.BlockingQueue 方法介紹
JavaBlockingQueue
提供了四組不同的方法用於向佇列中插入、移除、檢查佇列中包含某一元素物件。每一組方法在被呼叫之後的響應行為上有所不同,如下:
丟擲異常 | 返回特定值 | 阻塞後一直等待 | 阻塞後等待超時 | |
---|---|---|---|---|
插入物件 | add(o) | offer(o) | put(o) | offer(o, timeout, timeunit) |
移除物件 | remove(o) | poll() | take() | poll(timeout, timeunit) |
檢查物件存在 | element() | peek() |
上面的方法的四種行為分別的含義是
- 丟擲異常: 如果呼叫方法後不能立即響應結果(空佇列或滿佇列),則丟擲異常。
- 返回特定值: 如果呼叫方法後不能立即響應結果(空佇列或滿佇列),則返回特定的值(通常是true/false),true表示方法執行成功,否則表示方法執行失敗。
- 阻塞後一直等待: 如果呼叫方法後不能立即響應結果(空佇列或滿佇列),該方法將被阻塞一直處於等待狀態。
- 阻塞後等待超時: 如果呼叫方法後不能立即響應結果(空佇列或滿佇列),該方法將在一定時間範圍內被阻塞等待,也就是在超時時間範圍內阻塞。當超出超時時間之後,方法執行緒將不再阻塞,而是返回一個特定的值(通常是true/false),true表示方法執行成功,否則表示方法執行失敗。
另外,BlockingQueue
佇列不允許向其內部插入null,如果你向佇列中插入null,將會引發NullPointerException
異常。
一般的佇列都是從隊首放入物件,從隊尾獲取物件,BlockingQueue
不僅支援從隊首隊尾運算元據物件,還支援從佇列中其他任何位置運算元據。比如:你已經向佇列中放入一個物件並等待處理,但是出於某些特殊原因希望將這個物件從佇列中刪除掉。你可以呼叫remove(o)
方法來刪除佇列中的一個特定的o物件。當然我們的程式不能經常性的這樣做,因為佇列這種資料結構經常從中間位置運算元據的效率是極低的,所以除非必要不建議這樣做。
add(o)
BlockingQueueadd()
方法可以將o物件以引數的形式插入到佇列裡面,如果佇列裡面有剩餘空間,將被立即插入;如果佇列裡面沒有剩餘空間,add()
方法將跑出 IllegalStateException.
offer(o)
BlockingQueueoffer()
方法可以將o物件以引數的形式插入到佇列裡面,如果佇列裡面有剩餘空間,將被立即插入;如果佇列裡面沒有剩餘空間,offer()
方法將返回特定的值false
.
offer(o, long millis, TimeUnit timeUnit)
BlockingQueueoffer()
方法有另外一個版本的實現,存在超時時間的設定引數。這個版本的offer()
方法將o物件以引數的形式插入到佇列裡面,如果佇列裡面有剩餘空間,將被立即插入;如果佇列裡面沒有剩餘空間,呼叫offer方法的執行緒在超時時間內將被阻塞處於等到狀態,當阻塞時間大於超時時間之後,佇列內如果仍然沒有剩餘空間放入新物件,offer()
方法將返回false
.
put(o)
BlockingQueueput()
方法可以將o物件以引數的形式插入到佇列裡面,如果佇列裡面有剩餘空間,將被立即插入;如果佇列裡面沒有剩餘空間,呼叫put的方法的執行緒將被阻塞,直到BlockingQueue裡面騰出新的空間可以放入物件為止。
take()
BlockingQueuetake()
方法取出並移除佇列中的第一個元素(物件),如果BlockingQueue佇列中不包含任何的元素,呼叫take()
方法的執行緒將被阻塞,直到有新的元素物件插入到佇列中為止。
poll()
BlockingQueuepoll()
方法取出並移除佇列中的第一個元素(物件),如果BlockingQueue佇列中不包含任何的元素,poll()
方法將返回null
.
poll(long timeMillis, TimeUnit timeUnit)
BlockingQueuepoll(long timeMillis, TimeUnit timeUnit)
方法同樣存在一個超時時間限制的版本,正常情況下該方法取出並移除佇列中的第一個元素(物件)。如果BlockingQueue佇列中不包含任何的元素,在超時時間範圍內,如果仍然沒有新的物件放入佇列,這個版本的poll()
方法將被阻塞處於等待狀態;當阻塞時間大於超時時間之後,poll(long timeMillis, TimeUnit timeUnit)
返回null
remove(Object o)
BlockingQueueremove(Object o)
方法可以從佇列中刪除一個以引數形式給定的元素物件,remove()
方法使用o.equals(element)
將傳入引數o與佇列中的物件進行一一比對,從而判定要刪除的物件是否在佇列中存在,如果存在就從佇列中刪除並返回true,否則返回false。
需要注意的是:如果佇列中有多個與傳入引數equals相等的物件,只刪除其中一個,不會將佇列中所有匹配的物件都刪除。
peek()
BlockingQueuepeek()
方法將取出佇列中的第一個元素物件,但是並不會將其從佇列中刪除。如果佇列中目前沒有任何的元素,也就是空佇列,peek()
方法將返回null
.
element()
BlockingQueueelement()
方法將取出佇列中的第一個元素物件,但是並不會將其從佇列中刪除。如果佇列中目前沒有任何的元素,也就是空佇列,element()
方法將丟擲 NoSuchElementException.
contains(Object o)
BlockingQueuecontains(Object o)
方法用來判斷當前佇列中是否存在某個物件,該物件與傳入引數o相等(Objects.equals(o, element)
被用來判定物件的相等性)。遍歷佇列中的所有元素,一旦在佇列中發現匹配的元素物件,該方法將返回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()
方法將返回佇列目前還剩多少個可用空間用於放入新的物件。剩餘空間容量=佇列的總容量-已經被佔用的空間數量
歡迎關注我的部落格,裡面有很多精品合集
- 本文轉載註明出處(必須帶連線,不能只轉文字):字母哥部落格。
覺得對您有幫助的話,幫我點贊、分享!您的支援是我不竭的創作動力! 。另外,筆者最近一段時間輸出瞭如下的精品內容,期待您的關注。