1. 程式人生 > >Java阻塞佇列的學習筆記

Java阻塞佇列的學習筆記

## ArrayBlockingQueue的基本使用:

1、ArrayBlockingQueue是一個用陣列實現的有界阻塞佇列,內部按照先進先出的原則排序,take和put方法分別是新增和刪除元素的阻塞方法。

2、其內部是通過一個可重入鎖ReenterLock和Conditon條件佇列實現的,所有訪問佇列的時候存在公平和非公平的區別(預設非公平鎖)。

## LinkedBlockingQueue的基本使用:

1、LinkedBlockingQueue是一個用連結串列實現的有界阻塞佇列,內部按照先進先出的原則排序。

2、佇列的大小預設值為Integer.MAX_VALUE, 建議初始化一個定長的佇列,如果使用預設的大小,當消費者的消費能力小於生產者的生產能力時,可能會導致佇列的資料量越來越龐大,造成記憶體不足。

3、其吞吐量要高於ArrayBlockingQueue,原因是LinkedBlockingQueue的新增和刪除元素使用的是兩把不同的可重入鎖ReenterLock,可以併發執行。

## ArrayBlockingQueue和LinkedBlockingQueue的異同點:

1、佇列的初始化,ArrayBlockingQueue必須要指定大小,LinkedBlockingQueue可不指定大小,預設為Integer.MAX_VALUE,但是建議要給定大小,防止記憶體溢位的問題。

2、資料儲存的容器不同,ArrayBlockingQueue採用陣列來作為儲存資料的容器,而LinkedBlockingQueue採用的是一Node節點作為連線物件的連結串列。

3、由於ArrayBlockingQueue採用的是陣列的儲存容器,因此在插入和刪除元素時不會產生或銷燬額外的物件例項,而LinkedBlockingQueue則會生成一個額外的Node物件。這可能在長時間內需要高效併發的處理大批量資料時的效能會有影響,比如GC。

4、兩者的實現佇列的新增和刪除元素的鎖機制不一樣,ArrayBlockingQueue實現的佇列中的鎖是沒有分離的,就是說其新增和刪除用的同一把可重入鎖。而LinkedBlockingQueue實現的佇列中的新增元素和刪除元素的鎖是分離的,新增用putLock,移除則用takeLock, 這樣能大大提高佇列的吞吐量,也意味著在高併發的情況下生產者和消費者可以並行的操作佇列,以此來提高整個佇列的併發效能。

## 分享一個實際工作中用到阻塞佇列遇到的問題:

LinkedBlockingQueue與CountDownLatch放在一起使用,定義了一個定長的LinkedBlockingQueue,先往佇列裡放資料,等到到達佇列指定大小時,佇列進入阻塞,然而因為配合了CountDownLatch使用,佇列的消費被CountDownLatch的await()方法擋住了,導致互相在等待,最後丟擲了超時異常。

所以這裡要非常的小心,有界的阻塞佇列,不能把消費端阻斷了。