ArrayBlockingQueue是一個基於用數組實現的有界阻塞隊列。此隊列按照先進先出的原則對元素進行排序
一、成員變量
//存放元素的數組 final Object[] items; //隊頭 int takeIndex; //隊尾 int putIndex; //隊列中的元素個數 int count; // final ReentrantLock lock; //監視隊列是否爲空的監視器 private final Condition notEmpty; //監視隊列是否到達容量的監視器 private final Condition notFull;
二、構造方法
public ArrayBlockingQueue(int capacity, boolean fair) { if (capacity <= 0) throw new IllegalArgumentException(); this.items = new Object[capacity]; lock = new ReentrantLock(fair); notEmpty = lock.newCondition(); notFull = lock.newCondition(); }
根據傳入的fair的值來構造公平還是非公平的容量爲capacity的阻塞隊列
public ArrayBlockingQueue(int capacity) { this(capacity, false); }
只傳入容量的構造方法構造爲非公平的阻塞隊列
三、操作方法
private void enqueue(E x) { final Object[] items = this.items; items[putIndex] = x; if (++putIndex == items.length) putIndex = 0; count++; notEmpty.signal(); }
入隊列的操作方法,很簡單,將元素放到隊尾索引,將隊尾索引+1,如果入隊後隊列已滿,則重置隊尾,隊列長度加1,喚醒等待因爲無法取到元素二阻塞的線程。注意到,這個隊列是一個循環隊列
1、offer方法
public boolean offer(E e) { //入隊元素判空 checkNotNull(e); final ReentrantLock lock = this.lock; //獲取鎖 lock.lock(); try { //如果隊列已滿,返回false if (count == items.length) return false; else { //入隊,返回true enqueue(e); return true; } } finally { //釋放鎖 lock.unlock(); } }
可以看到,offer方法會返回特殊值並且不阻塞。offer方法在隊列已滿時,返回false,並沒有阻塞。入隊成功返回true。
2、put方法
public void put(E e) throws InterruptedException { //入隊元素判空 checkNotNull(e); final ReentrantLock lock = this.lock; //獲取鎖 lock.lockInterruptibly(); try { //如果隊列已滿,則阻塞該線程 while (count == items.length) notFull.await(); //隊列未滿,則入隊 enqueue(e); } finally { lock.unlock(); } }
可以看到,如果隊列已滿,put方法會阻塞線程。
private E dequeue() { final Object[] items = this.items; @SuppressWarnings("unchecked") E x = (E) items[takeIndex]; items[takeIndex] = null; if (++takeIndex == items.length) takeIndex = 0; count--; if (itrs != null) itrs.elementDequeued(); notFull.signal(); return x; }
dequeue是出隊的操作方法,很簡單,取出隊尾索引對應的值,將隊尾索引對應的元素置空,如果出隊索引到達隊列長度,則重置出隊索引,隊列長度減1,喚醒因入隊而阻塞的線程,最後返回對應的元素。
3、poll方法
public E poll() { final ReentrantLock lock = this.lock; //獲取鎖 lock.lock(); try { //如果隊列無元素返回null,不然調用dequeue return (count == 0) ? null : dequeue(); } finally { lock.unlock(); } }
可以看到,poll方法與offer方法類似,也是一個返回特殊值的方法,並且也不阻塞線程。如果隊列爲空返回null,不然出隊頭的元素
4、take方法
public E take() throws InterruptedException { final ReentrantLock lock = this.lock; //加鎖 lock.lockInterruptibly(); try { //如果隊列爲空,則阻塞線程 while (count == 0) notEmpty.await(); //隊列不爲空返回隊頭元素 return dequeue(); } finally { lock.unlock(); } }
可以看到,take方法和put方法類似,會阻塞線程。
還有等待多長時間的入隊和出隊方法,因爲只是加入了定時器,其餘和上述方法沒區別,所以我就不說了。
阻塞隊列提供了4類方法,如下圖所示