
在之前的文章中已經為大家介紹了java并發編程的工具:BlockingQueue接口、ArrayBlockingQueue、DelayQueue、LinkedBlockingQueue、PriorityBlockingQueue、SynchronousQueue,本文為系列文章第七篇。
`BlockingDeque`接口和[`BlockingQueue`](http://www.zimug.com/java/concurrency/java%e5%b9%b6%e5%8f%91%e7%bc%96%e7%a8%8b%e5%b7%a5%e5%85%b7%e7%b1%bbjuc%e4%b9%8b%e4%b8%80%ef%bc%9ablockingqueue%e9%98%bb%e5%a1%9e%e9%98%9f%e5%88%97/.html) 接口一樣都是在`java.util.concurrent`中定義的,它代表了一個線程安全的“雙端隊列”,以線程安全的方式向隊列中添加元素或獲取元素。本篇文章將帶大家進一步了解`BlockingDeque`。
> `deque`是 "Double Ended Queue "的縮寫。因此“雙端隊列”的含義就是可以從兩端(隊首或隊尾)插入和取出元素的隊列。
如果某個線程既生產又消費同一個隊列的元素,那么就可以使用`BlockingDeque`雙端隊列。如果生產線程需要在隊列的兩端插入,而消費線程需要從隊列的兩端刪除,也可以只使用`BlockingDeque`雙端隊列。參考下面的圖進行理解

一個線程生產元素并將它們插入到隊列兩端中的任何一端。如果`BlockingDeque`當前是滿的,插入線程將被阻塞,直到移除線程從`BlockingDeque`中取出一個元素。如果`BlockingDeque`當前為空,那么移除線程將被阻塞,直到插入線程將一個元素插入到`BlockingDeque`中。
## BlockingDeque 方法
`BlockingDeque`有4組不同的方法,用于插入、刪除和檢查deque中的元素。每組方法在所要求的操作不能被立即執行的情況下表現也有所不同。參考下面的表格
|隊首操作|拋出異常|返回特定值|阻塞后一直等待|阻塞后等待超時|
|---|---|---|---|---|
|插入對象|addFirst(o)|offerFirst(o)|putFirst(o)|offerFirst(o, timeout, timeunit)|
|移除對象|removeFirst(o)|pollFirst()|takeFirst()|pollFirst(timeout, timeunit)|
|檢查對象存在|getFirst()|peekFirst()|||
|隊尾操作|拋出異常|返回特定值|阻塞后一直等待|阻塞后等待超時|
|---|---|---|---|---|
|插入對象|addLast(o)|offerLast(o)|putLast(o)|offerLast(o, timeout, timeunit)|
|移除對象|removeLast(o)|pollLast()|takeLast()|pollLast(timeout, timeunit)|
|檢查對象存在|getLast()|peekLast()|||
大家可以看到,這些方法和和[`BlockingQueue`](http://www.zimug.com/java/concurrency/java%e5%b9%b6%e5%8f%91%e7%bc%96%e7%a8%8b%e5%b7%a5%e5%85%b7%e7%b1%bbjuc%e4%b9%8b%e4%b8%80%ef%bc%9ablockingqueue%e9%98%bb%e5%a1%9e%e9%98%9f%e5%88%97/.html) 的方法有些相似,只是在方法的基礎上加了xxxFirst和xxxLast,所以可以參考我之前的文章對比學習),上面的方法的四種行為分別的含義是
1. **拋出異常**: 如果調用方法后不能立即響應結果(空隊列或滿隊列),則拋出異常。
2. **返回特定值**: 如果調用方法后不能立即響應結果(空隊列或滿隊列),則返回特定的值(通常是true/false),true表示方法執行成功,否則表示方法執行失敗。
3. **阻塞后一直等待**: 如果調用方法后不能立即響應結果(空隊列或滿隊列),該方法將被阻塞一直處于等待狀態。
4. **阻塞后等待超時**: 如果調用方法后不能立即響應結果(空隊列或滿隊列),該方法將在一定時間范圍內被阻塞等待,也就是在超時時間范圍內阻塞。當超出超時時間之后,方法線程將不再阻塞,而是返回一個特定的值(通常是true/false),true表示方法執行成功,否則表示方法執行失敗。
## BlockingDeque繼承BlockingQueue
BlockingDeque接口繼承了BlockingQueue接口。這意味著你可以將BlockingDeque作為一個BlockingQueue使用。如果你這樣做,各種插入方法將把元素添加到deque的末尾,而移除方法將從deque的隊首移除元素。BlockingQueue接口的插入和刪除方法,就是這樣做的。
下面是BlockingQueue的方法在BlockingDeque實現中的作用對照表
|BlockingQueue|BlockingDeque|
|-----|-----|
|add()|addLast()|
|offer()|offerLast()|
|put()|putLast()|
|||
|remove()|removeFirst()|
|poll|pollFirst()|
|take()|takeFirst()|
|||
|element()|getFirst()|
|peek()|peekFirst()|
## BlockingDeque 接口實現類
`BlockingDeque`是一個接口,所以當我們真正對它進行實例化的時候,需要使用它的接口實現類。在`java.util.concurrent`包中的`LinkedBlockingDeque`方法實現了`BlockingDeque`接口。
其使用方法也與[`BlockingQueue`](http://www.zimug.com/java/concurrency/java%e5%b9%b6%e5%8f%91%e7%bc%96%e7%a8%8b%e5%b7%a5%e5%85%b7%e7%b1%bbjuc%e4%b9%8b%e4%b8%80%ef%bc%9ablockingqueue%e9%98%bb%e5%a1%9e%e9%98%9f%e5%88%97/.html) 大同小異,所以此處只做簡單的介紹。
~~~
//初始化一個LinkedBlockingDeque
BlockingDeque<String> deque = new LinkedBlockingDeque<String>();
deque.addFirst("1");//向隊首添加元素
deque.addLast("2"); //向隊尾添加元素
String two = deque.takeLast(); //從隊尾獲取元素
String one = deque.takeFirst(); //從隊首獲取元素
~~~
- 線程
- 1.進程和線程-鎖與信號量
- 2.Thread類線程狀態轉換
- 2.并發與并行-同步與異步
- 4.線程池
- 5.對象級別與類級別的同步鎖
- 6.創建線程的四種方式
- 7.臨界區-阻塞-活鎖-死鎖
- 2.JMM多線程模型
- JUC
- BlockingQueue
- ArrayBlockingQueue
- DelayQueue
- LinkedBlockingQueue
- PriorityBlockingQueue
- SynchronousQueue
- BlockingDeque
- ConcurrentHashMap
- CountDownLatch
- CyclicBarrier
- Exchanger
- AtomicInteger
- Lock
- Condition
- ReentrantLock讀寫鎖
- StampedLock
- Semaphore