ArrayBlockingQueue是阻塞队列BolockingQueue接口基于数组的实现,该特点由名字也可看出。
ArrayBlockingQueue继承了抽象类AbstractQueue并且实现了BlockingQueue接口。
创建一个ArrayBlockingQueue,必须要指定该队列长度,注意该队列长度是固定的,所以分配适当的长度非常重要,视具体的需求而定。
BlockingQueue<Integer> queue = new ArrayBlockingQueue(1024);
入队方法offer,还可以使用入队的其他方法
queue.offer(1);
queue.offer(3);
出队poll,还有其他方法入take
Integer poll = queue.poll();
try {
Integer take = queue.take();
} catch (InterruptedException e) {
e.printStackTrace();
}
/** 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;
ArrayBlockingQueue中存放元素的数组为一个Object[] items的数组,另外有一个ReentrantLock lock用于并发控制,Codition notEmpty是一个ConiditonObject类对象,内部维护了一个CLH链表,该聊表维护的是一个等待线程之间的关系,其源码可在AbstractQueuedSynchronizer抽象类中找到。
public ArrayBlockingQueue(int capacity) {
this(capacity, false);
}
//初始化容器数组和锁和CLH队列
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();
}
}
offer方法,和一般队列并没有区别,只是加了锁,锁的释放一定在finally代码块中,保证锁的释放。
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();
}
}
出队方法offer和take,注意二者的区别,take方法当队列为空的时候线程会等待,而poll方法在队列为空的时候直接返回null,对于阻塞队列如该队列长时间为空的情况下使用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();
}
}
总结ArrayBlockingQueue是阻塞队列基于数组的实现,需要注意的是内部使用的锁是ReentrantLock,并且了解不同出队方法的区别。