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中功能最強大的實現。
在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來進行定時操做。但願後面會開闢一個章節講講這裏面的想法。實在不行在講線程池部分確定會提到這個。