1. 程式人生 > >Java併發佇列Queue

Java併發佇列Queue

併發Queue

在併發佇列上JDK提供了兩套實現,一個是以ConcurrentLinkedQueue為代表的高效能佇列,一個是以BlockingQueue介面為代表的阻塞佇列,無論哪種都繼承自Queue。

注:暫只做解釋,後續會花時間進行完善

ConcurrentLinkedQueue

ConcurrentLinkedQueue:是一個適用於高併發場景下的佇列,通過無鎖的方式,實現了高併發狀態下的高效能,通常ConcurrentLinkedQueue效能好於BlockingQueue。它是一個基於連結節點的無界執行緒安全佇列。該佇列的元素遵循先進先出的原則。頭是最先加入的,尾是最近加入的,該佇列不允許null元素。

ConcurrentLinkedQueue重要方法:

add()和offer()都是加入元素的方法(在ConcurrentLinkedQueue中,這兩個方法沒有任何卻別)

poll()和peek()都是取頭元素節點,區別在於前者會刪除元素,後者不會。

BlockingQueue介面

ArrayBlockingQueue:基於陣列的阻塞佇列實現,在ArrayBlockingQueue內部,維護了一個定長陣列,以便快取佇列中的資料物件,其內部沒實現讀寫分離,也就意味著生產和消費不能完全並行,長度是需要定義的,可以指定先進先出或者先進後出,也叫有界佇列,在很多場合非常適合使用。

LinkedBlockingQueue:基於連結串列的阻塞佇列,同ArrayBlockingQueue類似,其內部也維持著一個數據緩衝佇列(該佇列由一個連結串列構成),LinkedBlockingQueue之所以能夠高效的處理併發資料,是因為其內部實現採用分離鎖(讀寫分離兩個鎖),從而實現生產者和消費者操作的完全並行執行。它是一個無界佇列。

SynchronousQueue:一種沒有緩衝的佇列,生產者產生的資料直接會被消費者獲取並消費。

PriorityBlockingQueue:基於優先順序的阻塞佇列(優先順序的判斷通過建構函式傳入的Compator物件來決定,也就是說傳入佇列的物件必須實現Comparable介面),在實現PriorityBlockingQueue時,內部控制執行緒同步的鎖採用的是公平鎖,它也是一個無界佇列。

DelayQueue:帶有延遲時間的Queue,其中的元素只有當其指定的延遲時間到了,才能夠從佇列中獲取到該元素。DelayQueue中的元素必須實現Delayed介面,DelayQueue是一個沒有大小限制的佇列,應用場景很多,比如對快取超時的資料進行移除、任務超時處理、空閒連線的關閉等等。

BlockingQueue介面的重要方法:

放入資料:

offer(anObject):表示如果可能的話,將anObject加到BlockingQueue裡,即如果BlockingQueue可以容納,則返回true,否則返回false。(本方法不阻塞當前執行方法的執行緒)

offer(E o,long timeout,TimeUnit unit),可以設定等待的時間,如果在指定的時間內,還不能往佇列中加入BlockingQueue,則返回失敗。

put(anObject):把anObject加到BlockingQueue裡,如果BlockingQueue沒有空間,則呼叫此方法的執行緒被阻塞知道BlockingQueue裡面有空間再繼續。

獲取資料:

poll(time):取走BlockingQueue裡排在首位的物件,若不能立即取出,則可以等time引數規定的時間,取不到時返回null;

poll(long timeout,TimeUnit unit):從BlockingQueue取出一個隊首的物件,如果在指定時間內,佇列一旦有資料可取,則立即返回佇列中的資料。否則直到時間超時還沒有資料可取,返回失敗。

take():取走BlockingQueue裡排在首位的物件,若BlockingQueue為空,阻斷進入等待狀態直到BlockingQueue有新的資料被加入;

drainTo():一次性從BlockingQueue獲取所有可用的資料物件(還可以指定獲取資料的個數),通過該方法,可以提升獲取資料效率:不需要多次分批加鎖或釋放鎖。

Deque雙端佇列

Deque允許在佇列的頭部或尾部進行出列和入隊操作。

LinkedBlockingDeque是一個執行緒安全的雙端佇列實現,可以說它是最為複雜的一種佇列,在內部實現維護了前端和後端節點,但是沒有實現讀寫分離,因此同一時間只能有一個執行緒對其進行操作。在高併發中效能要遠低於其它BlockingQueue。更要低於ConcurrentLinkedQueue,在JDK早期有一個非執行緒安全的Deque就是ArrayDeque了,java6裡添加了LinkedBlockingDeque來彌補多執行緒場景下執行緒安全的問題。