ps:在下文中分別以Array表明ArrayBlockingQueue,Link表明LinkedBlockingQueue,下文中再也不說明。java
Array和Link在併發場景中常用,他們的共同做用就是實現線程安全隊列。下面對這兩種隊列的實現進行對比分析。數組
int i = takeIndex; ... if (++i == items.length) i = 0; ...
這幾行在代碼在Array中幾乎每一個函數都會用到。意思不論是在讀取元素,或者存放元素,若是到達數組的最後一個元素,直接將索引移動到第一個位置。你可能會想,若是我一直往隊列中添加元素而不取,添加的元素個數超過了數組長度,會不會覆蓋以前添加的元素。在實際使用過程當中是不會出現這種狀況的,其內部使用了ReentrantLock的Condition,這部分在併發支持中介紹。安全
最大的區別就是Array內部只有一把鎖,offer和take使用同一把鎖,而Link的offer和take使用不一樣的鎖。數據結構
在作具體分析以前,先介紹一下ReentrantLock 和其Condition之間的關係。ReentrantLock內部維護了一個雙向鏈表,鏈表上的每一個節點都會保存一個線程,鎖在雙向鏈表的頭部自選,取出線程執行。而Condition內部一樣維持着一個雙向鏈表,可是其向鏈表中添加元素(await)和從鏈表中移除(signal)元素沒有像ReentrantLock那樣,保證線程安全,因此在調用Condition的await()和signal()方法時,須要在lock.lock()和lock.unlock()之間以保證線程的安全。在調用Condition的signal時,它從本身的雙向鏈表中取出一個節點放到了ReentrantLock的雙向鏈表中,因此在具體的運行過程當中無論ReentrantLock new 了幾個Condition其實內部公用的一把鎖。介紹完這個以後,我麼來分析ArrayBlockingQueue和LinkedBlockingQueue的內部實現不一樣。併發
先看其內部鎖的定義:函數
int count; lock = new ReentrantLock(fair); notEmpty = lock.newCondition(); notFull = lock.newCondition();
根據上面分析ReentrantLock和其Condition的關係,能夠看到放元素和取元素用的同一把鎖,沒法使放元素和取元素同時進行,只能前後相繼執行。性能
內部鎖定義:線程
/** Current number of elements */ private final AtomicInteger count = new AtomicInteger(); /** Lock held by take, poll, etc */ private final ReentrantLock takeLock = new ReentrantLock(); /** Wait queue for waiting takes */ private final Condition notEmpty = takeLock.newCondition(); /** Lock held by put, offer, etc */ private final ReentrantLock putLock = new ReentrantLock(); /** Wait queue for waiting puts */ private final Condition notFull = putLock.newCondition();
經過這種設置,能夠將在鏈表頭上放元素和在鏈表尾部取元素再也不競爭鎖,在必定程度上能夠加快數據處理。指針