queue是jdk 5以后引入的新的集合类,它属于java collections framework的成员,在collection集合中和list/set是同一级别的接口。通常来讲queue描述的是一种fifo的队列,当然不全都是,比如priorityqueue是按照优先级的顺序(或者说是自然顺序,借助于comparator接口)。
下图描述了java collections framework中queue的整个家族体系。
对于queue而言是在collection的基础上增加了offer/remove/poll/element/peek方法,另外重新定义了add方法。对于这六个方法,有不同的定义。
|
抛出异常
|
返回特殊值
|
操作描述
|
插入
|
add(e)
|
offer(e)
|
将元素加入到队列尾部
|
移除
|
remove()
|
poll()
|
移除队列头部的元素
|
检查
|
element()
|
peek()
|
返回队列头部的元素而不移除此元素
|
特别说明的是对于queue而言,规范并没有规定是线程安全的,为了解决这个问题,引入了可阻塞的队列blockingqueue。对于blockingqueue而言所有操作的是线程安全的,并且队列的操作可以被阻塞,直到满足某种条件。queue的另一个子接口deque描述的是一个双向的队列。与queue不同的是,deque允许在队列的头部增加元素和在队列的尾部删除元素。也就是说deque是一个双向队列。二者功能都有的队列就是blockingdeque,这种阻塞队列允许在队列的头和尾部分别操作元素,应该说是queue中功能最强大的实现。
在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来进行定时操作。希望后面会开辟一个章节讲讲这里面的想法。实在不行在讲线程池部分肯定会提到这个。
©2009-2014 imxylz
|求贤若渴