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類方法,如下圖所示
