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
|求賢若渴