java中的線程安全隊列

在併發編程種,有時候須要使用線程安全的隊列,若是實現一個線程安全的隊列有兩種方式:阻塞算法、非阻塞算法。使用阻塞算法的隊列能夠用一個鎖(出入隊列用同一把鎖),或兩個鎖(入隊和出隊用不一樣的鎖),非阻塞的實現方式則能夠用循環CAS的方式實現。html

一 非阻塞方式實現線程安全的隊列

ConcurrentLinkedQueue

 ConcurrentLinkedQueue由head節點和tail節點組成,每一個節點node由節點元素item和指向下一個節點next的引用組成。當咱們增長一個元素時,它會添加到隊列的末尾,當咱們取一個元素時,它會返回一個隊列頭部的元素。node

 

雖然ConcurrentLinkedQueue的性能很好,可是在調用size()方法的時候,會遍歷一遍集合,對性能損害較大,執行很慢,所以應該儘可能的減小使用這個方法,若是判斷是否爲空,最好用isEmpty()方法算法

 ConcurrentLinkedQueue不容許插入null元素,會拋出空指針異常。數據庫

 ConcurrentLinkedQueue是無界的,因此使用時,必定要注意內存溢出的問題。即對併發不是很大中等的狀況下使用,否則佔用內存過多或者溢出,對程序的性能影響很大,甚至是致命的。編程

 

 

二 阻塞方式實現線程安全的對列

JDK7提供了7個阻塞隊列,以下。
口 ArrayBlockingqueue:ー個由數組結構組成的有界阻塞隊列。
口 LinkedBlockingqueue:一個由鏈表結構組成的有界阻塞隊列。
口 PriorityBlockingqueue:一個支持優先級排序的無界阻塞隊列。
口 Delayqueue:ー個使用優先級隊列實現的無界阻塞隊列。
口 Synchronousqueue:一個不存儲元素的阻塞隊列。
口 Linkedtransferqueue:ー個由鏈表結構組成的無界阻塞隊列。
口 LinkedblockingDeque:ー個由鏈表結構組成的雙向阻塞隊列。segmentfault

 

ArrayBlockingQueue

 

LinkedBlockingQueue 

ConcurrentLinkedQueue、ArrayBlockingQueue、LinkedBlockingQueue 區別及使用場景

ArrayBlockingQueue extends AbstractQueue implements BlockingQueue LinkedBlockingQueue extends AbstractQueue implements BlockingQueue ConcurrentLinkedQueue extends AbstractQueue implements Queue

ConcurrentLinkedQueue基於CAS的無鎖技術,不須要在每一個操做時使用鎖,因此擴展性表現要更加優異,在常見的多線程訪問場景,通常能夠提供較高吞吐量。數組

LinkedBlockingQueue內部則是基於鎖,並提供了BlockingQueue的等待性方法。安全

 

ArrayBlockingQueue是初始容量固定的阻塞隊列,咱們能夠用來做爲數據庫模塊成功競拍的隊列,好比有10個商品,那麼咱們就設定一個10大小的數組隊列。多線程

ConcurrentLinkedQueue使用的是CAS原語無鎖隊列實現,是一個異步隊列入隊的速度很快出隊進行了加鎖,性能稍慢。併發

LinkedBlockingQueue也是阻塞的隊列,入隊和出隊都用了加鎖,當隊空的時候線程會暫時阻塞。

 


 

LinkedBlockingQueue與ArrayBlockingQueue的異同

相同:

一、LinkedBlockingQueue和ArrayBlockingQueue都實現了BlockingQueue接口;

二、LinkedBlockingQueue和ArrayBlockingQueue都是可阻塞的隊列 

  內部都是使用ReentrantLock和Condition來保證生產和消費的同步;

  當隊列爲空,消費者線程被阻塞;當隊列裝滿,生產者線程被阻塞;

使用Condition的方法來同步和通訊:await()和signal()

不一樣:

一、由上圖能夠看出,他們的鎖機制不一樣

  LinkedBlockingQueue中的鎖是分離的,生產者的鎖PutLock,消費者的鎖takeLock

  而ArrayBlockingQueue生產者和消費者使用的是同一把鎖;

二、他們的底層實現機制也不一樣

  LinkedBlockingQueue內部維護的是一個鏈表結構

在生產和消費的時候,須要建立Node對象進行插入或移除,大批量數據的系統中,其對於GC的壓力會比較大

而ArrayBlockingQueue內部維護了一個數組

在生產和消費的時候,是直接將枚舉對象插入或移除的,不會產生或銷燬任何額外的對象實例

 三、構造時候的區別

  LinkedBlockingQueue有默認的容量大小爲:Integer.MAX_VALUE,固然也能夠傳入指定的容量大小

ArrayBlockingQueue在初始化的時候,必須傳入一個容量大小的值

  看其提供的構造方法就能知道

四、執行clear()方法

  LinkedBlockingQueue執行clear方法時,會加上兩把鎖

五、統計元素的個數

 LinkedBlockingQueue中使用了一個AtomicInteger對象來統計元素的個數

 

 ArrayBlockingQueue則使用int類型來統計元素

 

 

https://www.jb51.net/article/90899.htm(好)

https://blog.csdn.net/jameshadoop/article/details/52729796

 

阻塞隊列的實現

https://segmentfault.com/a/1190000000373535

相關文章
相關標籤/搜索