remove()
或 poll()
所移除的元素。在 FIFO 隊列中,全部的新元素都插入隊列的末尾。其餘種類的隊列可能使用不一樣的元素放置規則。每一個 Queue 實現必須指定其順序屬性。Collection
操做外,隊列還提供其餘的插入、提取和檢查操做。每一個方法都存在兩種形式:一種拋出異常(操做失敗時),另外一種返回一個特殊值(null 或 false,具體取決於操做)。BlockingQueue
接口定義了那些等待元素出現或等待隊列中有可用空間的方法,這些方法擴展了此接口。 拋出異常 返回特殊值
插入:add(e) offer(e) 插入一個元素
移除:remove() poll() 移除和返回隊列的頭
檢查:element() peek() 返回但不移除隊列的頭。html
此接口是 Java Collections Framework 的成員。java
Java Queue接口擴展了Collection接口。Collection接口 externs Iterable接口。算法
子接口:BlockingQueue, Deque, BlobkingDequeue編程
一些最經常使用的Queue實現類是LinkedList,ArrayBlickingQueue, LinkedBlockingQueue,PriorityQueue, PriorityBlockingQueue。api
boolean add(E e) //將指定的元素插入此隊列(若是當即可行且不會違反容量限制),在成功時返回 true,若是當前沒有可用的空間,則拋出 IllegalStateException。 E element() //獲取,可是不移除此隊列的頭。 boolean offer(E e) //將指定的元素插入此隊列(若是當即可行且不會違反容量限制),當使用有容量限制的隊列時,此方法一般要優於 add(E),後者可能沒法插入元素,而只是拋出一個異常。 E peek() //獲取但不移除此隊列的頭;若是此隊列爲空,則返回 null。 E poll() //獲取並移除此隊列的頭,若是此隊列爲空,則返回 null。 E remove() //獲取並移除此隊列的頭。
一個基於連接節點的無界線程安全隊列。數組
一個基於連接節點的無界線程安全隊列。此隊列按照 FIFO(先進先出)原則對元素進行排序。隊列的頭部 是隊列中時間最長的元素。隊列的尾部是隊列中時間最短的元素。新的元素插入到隊列的尾部,隊列獲取操做從隊列頭部得到元素。當多個線程共享訪問一個公共 collection 時,ConcurrentLinkedQueue 是一個恰當的選擇。緩存
此隊列不容許使用 null 元素。安全
此實現採用了有效的「無等待 (wait-free)」算法,該算法基於 Maged M. Michael 和 Michael L. Scott 合著的 Simple, Fast, and Practical Non-Blocking and Blocking Concurrent Queue Algorithms 中描述的算法。數據結構
須要當心的是,與大多數 collection 不一樣,size 方法不是 一個固定時間操做。因爲這些隊列的異步特性,肯定當前元素的數量須要遍歷這些元素。多線程
ConcurrentLinkedQueue
以前的線程中的操做 happen-before 隨後經過另外一線程從 ConcurrentLinkedQueue
訪問或移除該元素的操做。線程安全的,volatile + CAS 可知入隊出隊函數都是操做volatile變量:head,tail。因此要保證隊列線程安全只須要保證對這兩個Node操做的可見性和原子性,因爲volatile自己保證可見性,因此只須要看下多線程下若是保證對着兩個變量操做的原子性。對於offer操做是在tail後面添加元素,也就是調用tail.casNext方法,而這個方法是使用的CAS操做,只有一個線程會成功,而後失敗的線程會循環一下,從新獲取tail,而後執行casNext方法。對於poll也是這樣的。
一個線性 collection,支持在兩端插入和移除元素。名稱 deque 是「double ended queue(雙端隊列)」的縮寫,一般讀爲「deck」。大多數 Deque 實現對於它們可以包含的元素數沒有固定限制,但此接口既支持有容量限制的雙端隊列,也支持沒有固定大小限制的雙端隊列。
隊列:此接口擴展了 Queue
接口。在將雙端隊列用做隊列時,將獲得 FIFO(先進先出)行爲。將元素添加到雙端隊列的末尾,從雙端隊列的開頭移除元素。
堆棧:雙端隊列也可用做 LIFO(後進先出)堆棧。應優先使用此接口而不是遺留 Stack
類。在將雙端隊列用做堆棧時,元素被推入雙端隊列的開頭並從雙端隊列開頭彈出。堆棧方法徹底等效於 Deque 方法,
LinkedList是基於鏈表實現的,從源碼能夠看出是一個雙向鏈表。除了當作鏈表使用外,它也能夠被看成堆棧、隊列或雙端隊列進行操做。
LinkedList不是線程安全的,繼承AbstractSequentialList實現List、Deque、Cloneable、Serializable。
併發隊列ConcurrentLinkedDeque,這是一個非阻塞,無鎖,無界 ,線程安全雙端操做的隊列。簡單說就是ConcurrentLinkedQueue的升級版,在JDK7以後才提供。該隊列也不容許空元素,並且size方法並非常量時間,其須要遍歷鏈表,此時併發修改鏈表會形成統計size不正確。一樣,bulk操做和equal以及toArray方法不保證原子性。
JDK7提供了7個阻塞隊列。分別是
Integer.MAX_VALUE
。 2 31-1 Integer.MAX_VALUE
。 2 31-1 Queue
,這兩個操做是:獲取元素時等待隊列變爲非空,以及存儲元素時等待空間變得可用(阻塞)。BlockingQueue 不接受 null 元素。試圖 add、put 或 offer 一個 null 元素時,某些實現會拋出 NullPointerException。null 被用做指示 poll 操做失敗的警惕值。
BlockingQueue 能夠是限定容量的。它在任意給定時間均可以有一個 remainingCapacity,超出此容量,便沒法無阻塞地 put 附加元素。沒有任何內部容量約束的 BlockingQueue 老是報告 Integer.MAX_VALUE 的剩餘容量。
BlockingQueue 實現主要用於生產者-使用者隊列,BlockingQueue 能夠安全地與多個生產者和多個使用者一塊兒使用。但它另外還支持 Collection
接口。所以,舉例來講,使用 remove(x) 從隊列中移除任意一個元素是有可能的。然而,這種操做一般不 會有效執行,只能有計劃地偶爾使用,好比在取消排隊信息時。
BlockingQueue 實現是線程安全的。全部排隊方法均可以使用內部鎖或其餘形式的併發控制來自動達到它們的目的。然而,大量的 Collection 操做(addAll、containsAll、retainAll 和 removeAll)沒有 必要自動執行,除非在實現中特別說明。所以,舉例來講,在只添加了 c 中的一些元素後,addAll(c) 有可能失敗(拋出一個異常)。
BlockingQueue 實質上不 支持使用任何一種「close」或「shutdown」操做來指示再也不添加任何項。這種功能的需求和使用有依賴於實現的傾向。例如,一種經常使用的策略是:對於生產者,插入特殊的 end-of-stream 或 poison 對象,並根據使用者獲取這些對象的時間來對它們進行解釋。
內存一致性效果:當存在其餘併發 collection 時,將對象放入 BlockingQueue
以前的線程中的操做 happen-before 隨後經過另外一線程從 BlockingQueue
中訪問或移除該元素的操做。
一個由數組支持的有界阻塞隊列。此隊列按 FIFO(先進先出)原則對元素進行排序。隊列的頭部 是在隊列中存在時間最長的元素。隊列的尾部 是在隊列中存在時間最短的元素。新元素插入到隊列的尾部,隊列獲取操做則是從隊列頭部開始得到元素。
這是一個典型的「有界緩存區」,固定大小的數組在其中保持生產者插入的元素和使用者提取的元素。一旦建立了這樣的緩存區,就不能再增長其容量。試圖向已滿隊列中放入元素會致使操做受阻塞;試圖從空隊列中提取元素將致使相似阻塞。
此類支持對等待的生產者線程和使用者線程進行排序的可選公平策略。默認狀況下,不保證是這種排序。然而,經過將公平性 (fairness) 設置爲 true 而構造的隊列容許按照 FIFO 順序訪問線程。公平性一般會下降吞吐量,但也減小了可變性和避免了「不平衡性」。
ArrayBlockingQueue內部有個循環數組items用來存放隊列元素,putIndex下標標示入隊元素下標,takeIndex是出隊下標,count統計隊列元素個數,從定義可知道並無使用volatile修飾,這是由於訪問這些變量使用都是在鎖塊內,並不存在可見性問題。
有個獨佔鎖lock用來對出入隊操做加鎖,這致使同時只有一個線程能夠訪問入隊出隊,
notEmpty,notFull條件變量用來進行出入隊的同步。另外構造函數必須傳入隊列大小參數,因此爲有界隊列,默認是Lock爲非公平鎖。
offer操做:在隊尾插入元素,若是隊列滿則返回false,否者入隊返回true。因爲在操做共享變量前加了鎖【final ReentrantLock lock = this.lock; 獲取獨佔鎖 lock.lock();】,因此不存在內存不可見問題,加過鎖後獲取的共享變量都是從主內存獲取的,而不是在CPU緩存或者寄存器裏面的值,釋放鎖後修改的共享變量值會刷新會主內存中。另外這個隊列是使用循環數組實現,因此計算下一個元素存放下標時候有些特殊。【i=putIndex; return(++i == items.length) ? 0 : i;】另外insert後調用 notEmpty.signal();是爲了激活調用notEmpty.await()阻塞後放入notEmpty條件隊列中的線程。
一個由連接節點支持的可選有界隊列。
一個基於已連接節點的、範圍任意的 blocking queue。此隊列按 FIFO(先進先出)排序元素。隊列的頭部 是在隊列中時間最長的元素。隊列的尾部 是在隊列中時間最短的元素。新元素插入到隊列的尾部,而且隊列獲取操做會得到位於隊列頭部的元素。連接隊列的吞吐量一般要高於基於數組的隊列,可是在大多數併發應用程序中,其可預知的性能要低。
可選的容量範圍構造方法參數做爲防止隊列過分擴展的一種方法。若是未指定容量,則它等於 Integer.MAX_VALUE
。除非插入節點會使隊列超出容量,不然每次插入後會動態地建立連接節點。
一個基於優先級堆的無界優先級阻塞隊列。
PriorityQueue
相同的順序規則,而且提供了阻塞獲取操做。雖然此隊列邏輯上是無界的,可是資源被耗盡時試圖執行 add 操做也將失敗(致使 OutOfMemoryError)。 Collection
和 Iterator
接口的全部可選 方法。iterator()
方法中提供的迭代器並不 保證以特定的順序遍歷 PriorityBlockingQueue 的元素。若是須要有序地進行遍歷,則應考慮使用 Arrays.sort(pq.toArray())。此外,可使用方法 drainTo 按優先級順序移除 所有或部分元素,並將它們放在另外一個 collection 中。
一個使用優先級隊列實現的無界阻塞隊列,只有在延遲期滿時才能從中提取元素。
DelayQueue隊列中每一個元素都有個過時時間,而且隊列是個優先級隊列,當從隊列獲取元素時候,只有過時元素纔會出隊列。
Delayed 元素的一個無界阻塞隊列,只有在延遲期滿時才能從中提取元素。該隊列的頭部 是延遲期滿後保存時間最長的 Delayed 元素。若是延遲都尚未期滿,則隊列沒有頭部,而且 poll 將返回 null。
當一個元素的 getDelay(TimeUnit.NANOSECONDS) 方法返回一個小於等於 0 的值時,將發生到期。即便沒法使用 take 或 poll 移除未到期的元素,也不會將這些元素做爲正常元素對待。例如,size 方法同時返回到期和未到期元素的計數。
此隊列不容許使用 null 元素。
一個不存儲元素、沒有內部容量的阻塞同步隊列。
SynchronousQueue的吞吐量高於LinkedBlockingQueue 和 ArrayBlockingQueue。
一個不存儲元素、沒有內部容量的阻塞隊列,其中每一個插入操做必須等待另外一個線程的對應移除操做 ,反之亦然。同步隊列沒有任何內部容量,甚至連一個隊列的容量都沒有。不能在同步隊列上進行 peek,由於僅在試圖要移除元素時,該元素才存在;除非另外一個線程試圖移除某個元素,不然也不能(使用任何方法)插入元素;也不能迭代隊列,由於其中沒有元素可用於迭代。隊列的頭 是嘗試添加到隊列中的首個已排隊插入線程的元素;若是沒有這樣的已排隊線程,則沒有可用於移除的元素而且 poll() 將會返回 null。對於其餘 Collection 方法(例如 contains),SynchronousQueue 做爲一個空 collection。
此隊列不容許 null 元素。
同步隊列相似於 CSP 和 Ada 中使用的 簡單彙集(rendezvous)機制信道。它很是適合於傳遞性設計,在這種設計中,在一個線程中運行的對象要將某些信息、事件或任務傳遞給在另外一個線程中運行的對象,它就必須與該對象同步。
對於正在等待的生產者和使用者線程而言,此類支持可選的公平排序策略。默認狀況下不保證這種排序。可是,使用公平設置爲 true 所構造的隊列可保證線程以 FIFO 的順序進行訪問。
LinkedTransferQueue是一個由鏈表結構組成的無界阻塞TransferQueue隊列。
tryTransfer方法。則是用來試探下生產者傳入的元素是否能直接傳給消費者。若是沒有消費者等待接收元素,則返回false。和transfer方法的區別是tryTransfer方法不管消費者是否接收,方法當即返回。而transfer方法是必須等到消費者消費了才返回。
對於帶有時間限制的tryTransfer(E e, long timeout, TimeUnit unit)方法,則是試圖把生產者傳入的元素直接傳給消費者,可是若是沒有消費者消費該元素則等待指定的時間再返回,若是超時還沒消費元素,則返回false,若是在超時時間內消費了元素,則返回true。
一個基於已連接節點的、任選範圍的阻塞雙端隊列。
Integer.MAX_VALUE
。只要插入元素不會使雙端隊列超出容量,每次插入後都將動態地建立連接節點。remove
、removeFirstOccurrence
、removeLastOccurrence
、contains
、iterator.remove()
以及批量操做,它們均以線性時間運行。