BlockingQueue是阻塞队列,首先是一个循环队列,支持入队出队操作;同时可以在队列满时阻塞入队,在队列空时阻塞出队。(类似一种消费者生产者模式)
ArrayBlockingQueue显然是通过数组来实现阻塞队列。
那么它是如何通过数组来实现队列呢?又如何实现阻塞入队出队呢?同时它又是线程安全的类,它是如何保证在多线程的情况下依然保证入队出队的正确呢?
public class ArrayBlockingQueue extends AbstractQueue
implements BlockingQueue, java.io.Serializable
/** The queued items 数组实现队列 */
final Object[] items;
/** items index for next take, poll, peek or remove 取元素时的指针(出队的指针) */
int takeIndex;
/** items index for next put, offer, or add 放入元素时的指针(入队)*/
int putIndex;
/** Number of elements in the queue 计数*/
int count;
/*
* Concurrency control uses the classic two-condition algorithm found in any textbook.
* 使用锁配合两个条件来进行配发控制
*/
/** Main lock guarding all access */
final ReentrantLock lock;
/** Condition for waiting takes 数组不空,才可以取元素*/
private final Condition notEmpty;
/** Condition for waiting puts 数组不满,才可以放入元素*/
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;
/**
* 构造一个给定容量(固定不变)的阻塞队列,默认使用非公平锁
*/
public ArrayBlockingQueue(int capacity) {
this(capacity, false);
}
/**
* 构造一个给定容量(固定不变)的阻塞队列,使用公平锁或非公平锁(根据入参fair决定)
* 公平锁是以FIFO的顺序获取锁,非公平锁以不确定的顺序获取
*/
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();
}
/**
* 构造一个阻塞队列,并且把集合中元素放入其中
*/
public ArrayBlockingQueue(int capacity, boolean fair,
Collection extends E> c) {
this(capacity, fair);
final ReentrantLock lock = this.lock;
lock.lock(); // Lock only for visibility, not mutual exclusion
try {
int i = 0;
try {
for (E e : c) {
//每一个位置都必须非空
checkNotNull(e);
items[i++] = e;
}
} catch (ArrayIndexOutOfBoundsException ex) {
throw new IllegalArgumentException();
}
count = i;
//移动指针
putIndex = (i == capacity) ? 0 : i;
} finally {
lock.unlock();
}
}
add、offer、put
public boolean add(E e) {
if (offer(e))
return true;
else
throw new IllegalStateException("Queue full");
}
public boolean offer(E e) {
checkNotNull(e);
final ReentrantLock lock = this.lock;
lock.lock();
try {
if (count == items.length)
return false;
else {
enqueue(e);
return true;
}
} finally {
lock.unlock();
}
}
/**
* Inserts the specified element at the tail of this queue, waiting
* for space to become available if the queue is full.
*
* @throws InterruptedException {@inheritDoc}
* @throws NullPointerException {@inheritDoc}
*/
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();
}
}
add、offer、put 都调用enqueue方法。
/**
* Inserts element at current put position, advances, and signals.
* Call only when holding lock.只有持有锁才能调用该方法
* 进行入队操作,并移动putIndex指针,计数加一,唤醒一个出队线程。
*/
private void enqueue(E x) {
// assert lock.getHoldCount() == 1;
// assert items[putIndex] == null;
final Object[] items = this.items;
items[putIndex] = x;
if (++putIndex == items.length)
putIndex = 0;
count++;
notEmpty.signal();
}
poll、take
public E poll() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
return (count == 0) ? null : dequeue();
} finally {
lock.unlock();
}
}
public E take() throws InterruptedException {
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
//当数组为空时,进行等待
while (count == 0)
notEmpty.await();
return dequeue();
} finally {
lock.unlock();
}
}
//poll和take都会调用dequeue,进行出队
/**
* Extracts element at current take position, advances, and signals.
* Call only when holding lock.只有持有锁时才能调用
* 取出元素,修改takeIndex指针,计数减一,唤醒入队等待线程。
*/
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;
if (++takeIndex == items.length)
takeIndex = 0;
count--;
if (itrs != null)
itrs.elementDequeued();
notFull.signal();
return x;
}
public E peek() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
return itemAt(takeIndex); // null when queue is empty
} finally {
lock.unlock();
}
}
public int size() {
//由于count字段没有使用volatile,所以也需要加锁获取值。
final ReentrantLock lock = this.lock;
lock.lock();
try {
return count;
} finally {
lock.unlock();
}
}
//限时等待进行入队
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)
return false;
//只等待相应的时间,如果时间过后队列还是满着,就返回false
nanos = notFull.awaitNanos(nanos);
}
enqueue(e);
return true;
} finally {
lock.unlock();
}
}
//限时等待 出队
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;
//只等待相应的时间,如果时间过后队列还是空着,就返回false
nanos = notEmpty.awaitNanos(nanos);
}
return dequeue();
} finally {
lock.unlock();
}