这个小节介绍Queue的最后一个工具,也是最强大的一个工具。从名称上就能够看到此工具的特色:双向并发阻塞队列。所谓双向是指能够从队列的头和尾同时操做,并发只是线程安全的实现,阻塞容许在入队出队不知足条件时挂起线程,这里说的队列是指支持FIFO/FILO实现的链表。java
首先看下LinkedBlockingDeque的数据结构。一般状况下从数据结构上就能看出这种实现的优缺点,这样就知道如何更好的使用工具了。安全
从数据结构和功能需求上能够获得如下结论:数据结构
有了上面的结论再来研究LinkedBlockingDeque的优缺点。并发
优势固然是功能足够强大,同时因为采用一个独占锁,所以实现起来也比较简单。全部对队列的操做都加锁就能够完成。同时独占锁也可以很好的支持双向阻塞的特性。高并发
凡事有利必有弊。缺点就是因为独占锁,因此不能同时进行两个操做,这样性能上就大打折扣。从性能的角度讲LinkedBlockingDeque要比LinkedBlockingQueue要低不少,比CocurrentLinkedQueue就低更多了,这在高并发状况下就比较明显了。工具
前面分析足够多的Queue实现后,LinkedBlockingDeque的原理和实现就不值得一提了,无非是在独占锁下对一个链表的普通操做。性能
有趣的是此类支持序列化,可是Node并不支持序列化,所以fist/last就不能序列化,那么如何完成序列化/反序列化过程呢?.net
清单1 LinkedBlockingDeque的序列化、反序列化线程
private void writeObject(java.io.ObjectOutputStream s)
throws java.io.IOException {
lock.lock();
try {
// Write out capacity and any hidden stuff
s.defaultWriteObject();
// Write out all elements in the proper order.
for (Node<E> p = first; p != null; p = p.next)
s.writeObject(p.item);
// Use trailing null as sentinel
s.writeObject(null);
} finally {
lock.unlock();
}
}对象private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
s.defaultReadObject();
count = 0;
first = null;
last = null;
// Read in all elements and place in queue
for (;;) {
E item = (E)s.readObject();
if (item == null)
break;
add(item);
}
}
清单1 描述的是LinkedBlockingDeque序列化/反序列化的过程。序列化时将真正的元素写入输出流,最后还写入了一个null。读取的时候将全部对象列表读出来,若是读取到一个null就表示结束。这就是为何写入的时候写入一个null的缘由,由于没有将count写入流,因此就靠null来表示结束,省一个整数空间。