深刻浅出 Java Concurrency (19): 并发容器 part 4 并发队列与Queue简介[转]

Queue是JDK 5之后引入的新的集合类,它属于Java Collections Framework的成员,在Collection集合中和List/Set是同一级别的接口。一般来说Queue描述的是一种FIFO的队列,固然不全都是,好比PriorityQueue是按照优先级的顺序(或者说是天然顺序,借助于Comparator接口)。java

下图描述了Java Collections Framework中Queue的整个家族体系。数组

对于Queue而言是在Collection的基础上增长了offer/remove/poll/element/peek方法,另外从新定义了add方法。对于这六个方法,有不一样的定义。缓存

 

抛出异常安全

返回特殊值spa

操做描述.net

插入线程

add(e)设计

offer(e)blog

将元素加入到队列尾部排序

移除

remove()

poll()

移除队列头部的元素

检查

element()

peek()

返回队列头部的元素而不移除此元素

特别说明的是对于Queue而言,规范并无规定是线程安全的,为了解决这个问题,引入了可阻塞的队列BlockingQueue。对于BlockingQueue而言全部操做的是线程安全的,而且队列的操做能够被阻塞,直到知足某种条件。Queue的另外一个子接口Deque描述的是一个双向的队列。与Queue不一样的是,Deque容许在队列的头部增长元素和在队列的尾部删除元素。也就是说Deque是一个双向队列。两者功能都有的队列就是BlockingDeque,这种阻塞队列容许在队列的头和尾部分别操做元素,应该说是Queue中功能最强大的实现。

 

image

在JDK 5以前LinkedList就已经存在,并且自己实现都是一种双向队列。因此到了JDK 5之后就将LinkedList同时实现Deque接口,这样LinkedList就又属于Queue的一部分了。

一般状况下Queue都是靠链表结构实现的,可是链表意味着有一些而外的引用开销,若是是双向链表开销就更大了。因此为了节省内存,一种方式就是使用固定大小的数组来实现队列。在这种状况下队列的大小是固定,元素的遍历经过数组的索引进行,很显然这是一种双向链表的模型。ArrayDeque就是这样一种实现。

另外ArrayBlockingQueue也是一种数组实现的队列,可是却没有改形成双向,仅仅实现了BlockingQueue的模型。理论上和ArrayDeque同样也应该容易改形成双向的实现。

PriorityQueue和PriorityBlockingQueue实现了一种排序的队列模型。这很相似与SortedSet,经过队列的Comparator接口或者Comparable元素来排序元素。这种状况下元素在队列中的出入就不是按照FIFO的形式,而是根据比较后的天然顺序来进行。

CocurrentLinkedQueue是一种线程安全却非阻塞的FIFO队列,这种队列一般实现起来比较简单,可是却颇有效。在接下来的章节会详细的描述它。

SynchronousQueue是一种特别的BlockingQueue,它只是把一个add/offer操做的元素直接移交给remove/take操做。也就是说它自己不会缓存任何元素,因此严格意义上说来说并非一种真正的队列。此队列维护一个线程列表,这些线程等待从队列中加入元素或者移除元素。简单的说,至少有一个remove/take操做时add/offer操做才能成功,一样至少有一个add/offer操做时remove/take操做才能成功。这是一种双向等待的队列模型,出队列等待加入等列,而入队列又等待出队列。这种队列的好处在于可以最大线程的保持吞吐量却又是线程安全的。因此对于一个须要快速处理的任务队列,SynchronousQueue是一个不错的选择。

 

BlockingQueue还有一种实现DelayQueue,这种实现容许每个元素(Delayed)带有一个延时时间,当调用take/poll的时候会检测队列头元素这个时间是否<=0,若是知足就是说已经超时了,那么此元素就能够被移除了,不然就会等待。特别说明的是这个头元素应该是最早被超时的元素(这个时间是绝对时间)。这个类设计很巧妙,被用于ScheduledFutureTask来进行定时操做。但愿后面会开辟一个章节讲讲这里面的想法。实在不行在讲线程池部分确定会提到这个。

相关文章
相关标签/搜索