本節學習ArrayBlockingQueue的源碼:
1.首先看類的定義
public class ArrayBlockingQueue<E> extends AbstractQueue<E>
implements BlockingQueue<E>, java.io.Serializable
可以看到類繼承了AbstractQueue且實現了接口BlockingQueue
public abstract class AbstractQueue<E>
extends AbstractCollection<E>
implements Queue<E> {
/**
* 構造方法
*/
protected AbstractQueue() {
}
/**
* 添加元素,如果添加成功,則返回true,否則異常
*/
public boolean add(E e) {
if (offer(e))
return true;
else
throw new IllegalStateException("Queue full");
}
/**
* 移除元素,如果移除成功,返回被移除的元素,否則異常
*/
public E remove() {
E x = poll();
if (x != null)
return x;
else
throw new NoSuchElementException();
}
/**
* 獲取元素,如果獲取到元素,則返回,否則異常
*/
public E element() {
E x = peek();
if (x != null)
return x;
else
throw new NoSuchElementException();
}
/**
* 清空隊列
*/
public void clear() {
while (poll() != null)
;
}
/**
* 添加元素,如果添加成功,則返回true,否則返回false,或者異常
*/
public boolean addAll(Collection<? extends E> c) {
if (c == null)
throw new NullPointerException();
if (c == this)
throw new IllegalArgumentException();
boolean modified = false;
for (E e : c)
if (add(e))
modified = true;
return modified;
}
}
2.類的變量信息
/** 使用數組保存隊列元素 */
final Object[] items;
/** 下一個去除或者移除的元素的下標位置 */
int takeIndex;
/** 下一個添加的元素的下標位置 */
int putIndex;
/** 隊列中元素的個數 */
int count;
/** 控制所有訪問的重入鎖 */
final ReentrantLock lock;
/** 取出元素的條件 */
private final Condition notEmpty;
/** 添加元素的條件 */
private final Condition notFull;
/**
* Shared state for currently active iterators, or null if there
* are known not to be any. Allows queue operations to update
* iterator state.
*/
transient Itrs itrs = null;
3.添加元素的四個方法:
3.1 add 調用的抽象隊列中的添加方法,會拋異常
public boolean add(E e) {
return super.add(e);
}
3.2 offer如果隊列滿了,則直接返回false。
public boolean offer(E e) {
checkNotNull(e);//元素判空,如果爲空,則拋空指針異常
final ReentrantLock lock = this.lock;
lock.lock();
try {
if (count == items.length)//如果隊列元素滿了,則返回false
return false;
else {
enqueue(e);//否則
return true;
}
} finally {
lock.unlock();
}
}
private void enqueue(E x) {
// assert lock.getHoldCount() == 1;
// assert items[putIndex] == null;
final Object[] items = this.items;
items[putIndex] = x;//設置putIndex下標元素爲x
if (++putIndex == items.length)//如果putIndex加1後的長度等於數組長度,則設置putIndex爲0
putIndex = 0;
count++;//數組元素個數+1
notEmpty.signal();//喚醒取元素條件
}
3.3 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();
}
}
3.4 offer可終端,超時時間內可以阻塞等待,超時後如果隊列還是滿的,則返回false。
public boolean offer(E e, long timeout, TimeUnit unit)
throws InterruptedException {
checkNotNull(e);//非空校驗
long nanos = unit.toNanos(timeout);//超時時間
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
while (count == items.length) {
if (nanos <= 0)//如果隊列滿了且超過等待時間,則返回false
return false;
nanos = notFull.awaitNanos(nanos);//否則添加元素的條件等待nanos時間
}
enqueue(e);
return true;
} finally {
lock.unlock();
}
}
4.取元素的幾個方法
4.1 poll 如果隊列中沒有元素,則返回null
public E poll() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
return (count == 0) ? null : dequeue();
} finally {
lock.unlock();
}
}
private E dequeue() {
// assert lock.getHoldCount() == 1;
// assert items[takeIndex] != null;
final Object[] items = this.items;
@SuppressWarnings("unchecked")
E x = (E) items[takeIndex];
items[takeIndex] = null;//設置元素爲null
if (++takeIndex == items.length)
takeIndex = 0;
count--;
if (itrs != null)
itrs.elementDequeued();
notFull.signal();//添加元素的條件喚醒
return x;
}
4.2 take 可中斷,如果隊列爲空,則進入等待。 public E take() throws InterruptedException {
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
while (count == 0)//如果沒有可移除的元素,則移除元素的條件等待
notEmpty.await();
return dequeue();//移除元素
} finally {
lock.unlock();
}
}
4.3 poll 可中斷,如果隊列爲空,在等待時間內會進入等待狀態,過了等待時間返回null。
public E poll(long timeout, TimeUnit unit) throws InterruptedException {
long nanos = unit.toNanos(timeout);
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
while (count == 0) {
if (nanos <= 0)
return null;
nanos = notEmpty.awaitNanos(nanos);
}
return dequeue();
} finally {
lock.unlock();
}
}
4.4 remove
public boolean remove(Object o) {
if (o == null) return false;
final Object[] items = this.items;
final ReentrantLock lock = this.lock;
lock.lock();
try {
if (count > 0) {//如果隊列不爲空
final int putIndex = this.putIndex;
int i = takeIndex;
do {
if (o.equals(items[i])) {
removeAt(i); 移除元素
return true;
}
if (++i == items.length)
i = 0;
} while (i != putIndex);
}
return false;
} finally {
lock.unlock();
}
}
void removeAt(final int removeIndex) {
// assert lock.getHoldCount() == 1;
// assert items[removeIndex] != null;
// assert removeIndex >= 0 && removeIndex < items.length;
final Object[] items = this.items;
if (removeIndex == takeIndex) {
// removing front item; just advance
items[takeIndex] = null;
if (++takeIndex == items.length)
takeIndex = 0;
count--;
if (itrs != null)
itrs.elementDequeued();
} else {
// an "interior" remove
// slide over all others up through putIndex.
final int putIndex = this.putIndex;
for (int i = removeIndex;;) {
int next = i + 1;
if (next == items.length)
next = 0;
if (next != putIndex) {
items[i] = items[next];
i = next;
} else {
items[i] = null;
this.putIndex = i;
break;
}
}
count--;
if (itrs != null)
itrs.removedAt(removeIndex);
}
notFull.signal();
}
5 其他方法
5.1 peek 返回下個要移除的元素值。
public E peek() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
return itemAt(takeIndex); // null when queue is empty
} finally {
lock.unlock();
}
}
5.2 size 返回隊列元素的個數
public int size() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
return count;
} finally {
lock.unlock();
}
}
5.3 remainingCapacity 返回隊列剩餘的空間
public int remainingCapacity() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
return items.length - count;
} finally {
lock.unlock();
}
}
5.4 contains判斷隊列中是否包含元素o
public boolean contains(Object o) {
if (o == null) return false;
final Object[] items = this.items;
final ReentrantLock lock = this.lock;
lock.lock();
try {
if (count > 0) {
final int putIndex = this.putIndex;
int i = takeIndex;
do {
if (o.equals(items[i]))
return true;
if (++i == items.length)
i = 0;
} while (i != putIndex);
}
return false;
} finally {
lock.unlock();
}
}
5.5 clear 清空隊列,且喚醒所有添加數據的條件
public void clear() {
final Object[] items = this.items;
final ReentrantLock lock = this.lock;
lock.lock();
try {
int k = count;
if (k > 0) {
final int putIndex = this.putIndex;
int i = takeIndex;
do {
items[i] = null;
if (++i == items.length)
i = 0;
} while (i != putIndex);
takeIndex = putIndex;
count = 0;
if (itrs != null)
itrs.queueIsEmpty();
for (; k > 0 && lock.hasWaiters(notFull); k--)
notFull.signal();
}
} finally {
lock.unlock();
}
}
總結:
有界阻塞隊列,底層數據結構是數組。
同步控制使用的重入鎖和condition。