Queue簡介
Java集合框架中的隊列來自于最基本的Queue接口:
public interface Queue<E> extends Collection<E> {
boolean add(E e);
boolean offer(E e);
E remove();
E poll();
E element();
E peek();
}
-
add/offer添加元素,add等同于Collection中的add方法,隊列滿了之后調(diào)用add方法會拋出異常,offer則返回false表示添加失敗 -
remove/poll刪除第一個元素,remove等同于Collection中的remove方法,隊列為空以后調(diào)用會拋出異常,而poll會返回null -
element/peek查詢頭部元素,同上,但是不移除元素。
util包中的Queue
Java中常用的隊列分為兩種,一種是util包中的常規(guī)隊列,主要包括PriorityQueue,ArrayDeque。
PriorityQueue
-
PriorityQueue是有序隊列,數(shù)據(jù)存放順序由指定的Comparator(如果有)或自然排序決定,而不是插入時的順序。 -
PriorityQueue不能插入null值,會拋出異常 -
PriorityQueue采用數(shù)組存儲數(shù)據(jù),沒有同步方法,是線程不安全的。
ArrayDequeue
ArrayDequeue是雙端隊列,繼承了Dequeue接口,除了Queue中的方法之外,它還有一些addFirst/ offerFirst,removeLast/pollLast 等指定頭尾的操作。
它內(nèi)部也是采用數(shù)組存儲數(shù)據(jù),存儲順序為插入順序,同樣不能接受null值,并且線程不安全
Concurrent包中的Queue
Concurrent包中又分為兩類隊列,一類是阻塞隊列,實現(xiàn)了BlockingQueue接口,另一類是非阻塞隊列,只是加了同步。
非阻塞隊列
非阻塞隊列有ConcurrentLinkedDeque和ConcurrentLinkedQeque,一個單端一個雙端隊列,都是先進先出原則,不會阻塞,線程安全
阻塞隊列
-
ArrayBlockingQueue數(shù)組實現(xiàn)的有界隊列,必須指定容量,可以實現(xiàn)公平鎖或非公平鎖,默認非公平鎖 -
LinkedBlockingQueue鏈表實現(xiàn)的有界隊列,默認容量為MAX。采用鏈表存儲的方式,在添加移除數(shù)據(jù)時會產(chǎn)生大量的node節(jié)點對象,內(nèi)存消耗比數(shù)組要嚴重。LinkedBlockingQueue的put和take鎖是分離的,多線程讀寫效率比ArrayBlockingQueue要高。 -
LinkedBlockingDeque同上,雙端隊列 -
PriorityBlockingQueue無界的有序隊列,按照指定的Comparator或自然排序存儲數(shù)據(jù),默認初始容量為11,可以指定初始容量,存滿后自動擴容。 -
SynchronousQueue不存儲元素,每一個put操作都要等待take取走數(shù)據(jù)之后才能進行 -
DelayQueue延時隊列 LinkedTransferQueue
他們都繼承自BlockingQueue接口:
public interface BlockingQueue<E> extends Queue<E> {
boolean add(E e);
boolean offer(E e);
void put(E e) throws InterruptedException;
boolean offer(E e, long timeout, TimeUnit unit)
throws InterruptedException;
E take() throws InterruptedException;
E poll(long timeout, TimeUnit unit)
throws InterruptedException;
boolean remove(Object o);
}
除了繼承自Queue接口的方法以外,它新增了阻塞方法,put和take,另外新增了可以指定超時時間的offer和poll方法。
延時隊列DelayQueue:
它內(nèi)部采用了PriorityBlockingQueue存儲數(shù)據(jù),按照延時時間的順序來存放。存放元素必須是實現(xiàn)了Delayed接口的對象。Delayed接口本身只有一個方法,另外它還繼承了Comparable,也就是說它的存儲對象必須實現(xiàn)以下兩個方法:
long getDelay(TimeUnit unit);
public int compareTo(T o);
getDelay返回值為long類型,只有當返回值小于等于0的時候,才認為該元素的延時時間已經(jīng)結束,可以被取出了,如果所有元素都處于等待狀態(tài),那么取出的值為null。
compareTo決定了元素存放的順序,通常是按delay時間升序排列。
LinkedTransferQueue:
除了阻塞隊列的通用方法之外,它多了一個transfer功能:
transfer(E e):若當前存在一個正在等待獲取的消費者線程,即立刻移交;否則,會插入當前元素e到隊列尾部,并且進入阻塞狀態(tài),直到有消費者線程取走該元素。
tryTransfer(E e):若當前存在一個正在等待獲取的消費者線程(take()或者poll()),使用該方法會即刻轉(zhuǎn)移/傳輸對象元素e;若不存在,則返回false,并且數(shù)據(jù)不插入隊列,非阻塞方法。
tryTransfer(E e, long timeout, TimeUnit unit):若當前存在一個正在等待獲取的消費者線程,會立即傳輸給它;否則將插入元素e到隊列尾部,并且等待被消費者線程獲取消費掉;若在指定的時間內(nèi)元素e無法被消費者線程獲取,則返回false,同時該元素被移除。
hasWaitingConsumer():判斷是否存在消費者線程。
getWaitingConsumerCount():獲取所有等待獲取元素的消費線程數(shù)量。