![](https://cdn.zimug.com/wx-zimug.png)
在之前的文章中已经为大家介绍了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`双端队列。参考下面的图进行理解
![](http://cdn.zimug.com/6788ae32d22b8b7d399ca9a7b5f4502a)
一个线程生产元素并将它们插入到队列两端中的任何一端。如果`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