java併發編程工具類JUC第一篇:BlockingQueue阻塞隊列

Java BlockingQueue接口java.util.concurrent.BlockingQueue表示一個能夠存取元素,而且線程安全的隊列。換句話說,當多線程同時從 JavaBlockingQueue中插入元素、獲取元素的時候,不會致使任何併發問題(元素被插入屢次、處理屢次等問題)。vue

從java BlockingQueue能夠引伸出一個概念:阻塞隊列,是指隊列自己能夠阻塞線程向隊列裏面插入元素,或者阻塞線程從隊列裏面獲取元素。好比:當一個線程嘗試去從一個空隊列裏面獲取元素的時候,這個線程將被阻塞直到隊列內元素數量再也不爲空。固然,線程是否會被阻塞取決於你調用什麼方法從BlockingQueue獲取元素,有的方法會阻塞線程,有的方法會拋出異常等等,下文咱們會詳細介紹。java

1、BlockingQueue 接口實現類

本文不會去介紹如何本身實現BlockingQueue接口,JUC已經爲咱們作好了相關的一些接口實現類。
BlockingQueue是一個java接口,當咱們須要使用阻塞隊列的時候,可使用它的實現類。java.util.concurrent包裏面有以下的一些實現類實現了BlockingQueue接口。redis

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

在本文以及後續的文章中,會依次爲你們介紹這些實現類的做用及使用場景,期待您的關注。spring

2、BlockingQueue 應用場景介紹

BlockingQueue一般被應用在一個線程生產對象放入隊列,與此同時另外一個線程消費隊列內的對象的場景下。下面的這張圖說明了使用場景:
後端

生產者線程不斷的生產新的對象,並將他們插入到BlockingQueue,直到隊列中object的數量達到隊列存儲容量的上限。也就是說當隊列中對象達到容量上限的時候,生產者線程將被阻塞,不能再向隊列中插入新的對象。生產者線程將保持阻塞等待狀態,直到消費者線程從隊列中拿走Object,讓隊列有空餘位置放入新的對象。安全

消費者線程不斷的從BlockingQueue取出對象並將其進行處理。若是消費者線程嘗試從一個空隊列中獲取一個對象,消費者線程將被阻塞處於等待狀態,直到生產者向隊列中放入一個新的對象。springboot

因此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()

上面的方法的四種行爲分別的含義是併發

  1. 拋出異常: 若是調用方法後不能當即響應結果(空隊列或滿隊列),則拋出異常。
  2. 返回特定值: 若是調用方法後不能當即響應結果(空隊列或滿隊列),則返回特定的值(一般是true/false),true表示方法執行成功,不然表示方法執行失敗。
  3. 阻塞後一直等待: 若是調用方法後不能當即響應結果(空隊列或滿隊列),該方法將被阻塞一直處於等待狀態。
  4. 阻塞後等待超時: 若是調用方法後不能當即響應結果(空隊列或滿隊列),該方法將在必定時間範圍內被阻塞等待,也就是在超時時間範圍內阻塞。當超出超時時間以後,方法線程將再也不阻塞,而是返回一個特定的值(一般是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() 方法將返回隊列目前還剩多少個可用空間用於放入新的對象。剩餘空間容量=隊列的總容量-已經被佔用的空間數量

歡迎關注個人博客,裏面有不少精品合集

本文轉載註明出處(必須帶鏈接,不能只轉文字):字母哥博客 - zimug.com

以爲對您有幫助的話,幫我點贊、分享!您的支持是我不竭的創做動力! 。另外,筆者最近一段時間輸出了以下的精品內容,期待您的關注。