標籤:java queue
Queue概覽
650) this.width=650;" src="http://s3.51cto.com/wyfs02/M02/8A/BA/wKioL1g6QInzGoE-AABumATAFWk847.png" title="搜狗_2016-11-27_10-09-19.png" alt="wKioL1g6QInzGoE-AABumATAFWk847.png" />
,在並發隊列上,JDK提供了2套實現,一個是以ConcurrentLinkedQueue為代表的高效能非阻塞隊列,一個是以BlockingQueue介面為代表的阻塞隊列,無論哪種都繼承自Queue。使用阻塞演算法的隊列可以用一個鎖(入隊和出隊用同一把鎖)或兩個鎖(入隊和出隊用不同的鎖)等方式來實現,而非阻塞的實現方式則可以使用迴圈CAS的方式來實現,下面我們來一一分析。
ConcurrentLinkedQueue
一個適用於高並發情境下的隊列,通過無鎖的方式(CAS+volatile),實現了高並發下的高效能,通常ConcurrentLinkedQueue的效能好於BlockingQueue。
它是一個基於連結節點的無界安全執行緒隊列,遵循先進先出的原則,頭是最先加入的,尾是最近加入的,不允許加入null元素。
注意add()/offer()都是加入元素的方法,這裡沒有區別;poll()/peek()是取出頭元素的方法,區別點在於poll會刪除元素,而peek不會。
要特別注意到由於它的非阻塞性,並不像其他普通集合那樣,擷取隊列的SIZE的方法並不是常量時間的花費,而是O(N)的,因此我們應該儘可能避免使用size()方法,可以考慮使用isEmpty()代替。
雖然使用到了CAS+VOLATILE的機制避免了鎖,但是我們要明白的是,這隻是保證單個操作,如peek()的安全,但是多個操作如果想保證的話,需要使用鎖機制來達到同步的效果。
BlockingQueue API
入隊:
offer(E e):如果隊列沒滿,立即返回true; 如果隊列滿了,立即返回false-->不阻塞
put(E e):如果隊列滿了,一直阻塞,直到數組不滿了或者線程被中斷-->阻塞
offer(E e, long timeout, TimeUnit unit):在隊尾插入一個元素,,如果數組已滿,則進入等待,直到等待時間逾時
出隊:
poll():非阻塞拿資料,立即返回
take():阻塞拿資料
poll(long timeout, TimeUnit unit):帶有一定逾時時間的poll拿取資料
ArrayBlockingQueue
基於數組的阻塞隊列實現,在其內部維護了一個定長數組,以便緩衝隊列中的資料對象,由於ArrayBlockingQueue內部只有一個鎖對象(ReentrantLock),因此讀寫沒有實現分離,也就意味著生產消費不能完全並行。由於長度需要定義,因此也叫有界隊列。
LinkedBlockingQueue
基於鏈表的阻塞隊列實現,同ArrayBlockingQueue類似,其內部也維持著一個資料緩衝隊列(鏈表構成)。
LinkedBlockingQueue之所以較ArrayBlockingQueue更加高效的處理並發資料,是因為內部實現採用了2把鎖,也就是實現了入隊、出隊分別上鎖,即讀寫分離,從而生產者、消費者完全到達了並行。
無需定義長度,也叫無界隊列。當然不定義長度時,需要注意下生產者的速度和消費者的速度,因為預設情況下隊列長度是Integer.MAX_VALUE。
SynchronousQueue
一個沒有緩衝的隊列,生產者生產的資料會直接被消費者擷取到並消費。它是一個輕量級的阻塞隊列,因為不具備容量,在用法上,只能是一個線程阻塞著取元素,等待另一個線程往隊列裡面放入一個元素,然後會被等待著的線程立即取走,其實就是實現了線程間的輕量級的單元素交換。
PriorityBlockingQueue
基於優先順序的阻塞隊列(優先順序的判斷通過建構函式傳入的Compator對象決定,也就是傳入隊列中對象必須實現Comparable介面)。
在實現PriorityBlockingQueue時,內部控制線程同步的鎖採用的是公平鎖,也是一個無界的隊列。
通俗的來說,不是先進先出的隊列了,而是誰的優先順序低誰先出去。那麼可以思考下,是否每次add/offer都會進行一次排序呢?我們是否需要按照優先順序進行全排序呢?實際上,可以大致看一看add/take方法,會瞭解到PriorityBlockingQueue的設計思想:在add時,並不進行排序處理,當進行take時,選擇優先順序最小的拿出來而已,這樣既避免了在add時花費時間排序,又在take時節省了時間,因為並沒有全排序,僅僅是挑選了一個優先順序低的元素而已。
DelayQueue
帶有延遲時間的Queue,其中的元素只有當指定的延遲時間到了,才能從隊列中擷取到該元素。隊列中的元素必須實現Delayed介面,沒有大小限制。本質上來說,是藉助於PriorityBlockingQueue來實現的,以延遲時間作為優先順序。延遲隊列的應用情境很多,比如緩衝逾時的資料進行移除,任務逾時處理,空閑串連的關閉等等。
本文出自 “學海無涯 心境無限” 部落格,請務必保留此出處http://zhangfengzhe.blog.51cto.com/8855103/1878323
Java Queue 使用總結