ArrayBlockingQueue概述
- 这是一个由有限的数组、且支持阻塞的队列。 这个队列排列元素FIFO(先进先出), 新元素插入队列的尾部,队列检索操作获取队列头部的元素。
- 这是一个经典的“有界缓冲区”,其中固定大小的数组保存由生产者插入的元素并由消费者提取。
- 创建后,容量无法更改。 当队列已满时,put操作会使队列阻塞; 而尝试take操作从空队列的队列也同样发类似地阻塞。
- 此类支持可选的公平策略,用于订阅和等待的生产者和消费者线程。 公平设置为true的队列以FIFO顺序授予线程访问权限。 公平性通常会降低吞吐量,但可以避免饥饿。
- 这个类是Java Collections Framework的成员,在Java1.5提供。
类结构
public class ArrayBlockingQueue<E>
extends AbstractQueue<E>
implements BlockingQueue<E>, Serializable
特征
- 内部数据结构: 它基于环形数组来存储元素。数组的第一个和最后一个元素在逻辑上相邻;每当从队列中添加/删除元素时,队列都会使头元素/尾元素的索引前进。当任一索引使数组中的最后一个元素前进时,它将从0重新开始。这种机制比使用常规数组更好,因为每当移除磁头时队列都不必移动所有元素。但如果您删除中间的一个元素(通过Iterator.remove),则它必须移动这些元素;
- 容量: ArrayBlockingQueue可以容纳的元素数量有限制,因为在构造此类的新对象时必须指定容量。因此,ArrayBlockingQueue是有界的BlockingQueue;
- 顺序: 由于它基于数组,因此元素按FIFO(先进先出)顺序排列;
- 操作: 队列插入和删除在固定时间内执行(非常快);
- Iterator: 由ArrayBlockingQueue 返回的迭代器是弱一致性的,这意味着该迭代器可以与其他操作并发使用。它永远不会抛出ConcurrentModificationException并支持remove操作。
成员属性
构造方法
ArrayBlockingQueue(int capacity)
创建具有给定(固定)容量和默认访问策略的 ArrayBlockingQueue 。
ArrayBlockingQueue(int capacity, boolean fair)
创建一个 ArrayBlockingQueue具有给定(固定)容量和指定访问策略。
ArrayBlockingQueue(int capacity, boolean fair, Collection<? extends E> c)
创建一个 ArrayBlockingQueue具有给定(固定)容量,指定访问策略和最初包含给定集合中的元素,添加在收集迭代器的遍历顺序。
常用方法
boolean add(E e)
在插入此队列的尾部,如果不超过该队列的容量,则返回true功,如果此队列已满,抛出 IllegalStateExceptio。
boolean offer(E e)
如果可以在不超过队列容量的情况下立即将其指定的元素插入该队列的尾部,则在成功时 false如果该队列已满,则返回 true 。
boolean offer(E e, long timeout, TimeUnit unit)
在该队列的尾部插入指定的元素,等待指定的等待时间,以使空间在队列已满时变为可用。
void put(E e)
在该队列的尾部插入指定的元素,如果队列已满,则阻塞。
E peek()
检索但不删除此队列的头,如果此队列为空,则返回 null 。
E poll()
检索并删除此队列的头,如果此队列为空,则返回 null 。
E poll(long timeout, TimeUnit unit)
检索并删除此队列的头,等待指定的等待时间(如有必要)使元素变为可用。
E take()
检索并删除此队列的头,如有必要,等待元素可用。
void clear()
从这个队列中原子地删除所有的元素。
boolean remove(Object o)
从该队列中删除指定元素的单个实例(如果存在)。
boolean contains(Object o)
如果此队列包含指定的元素,则返回 true 。
Iterator<E> iterator()
以适当的顺序返回该队列中的元素的迭代器。
Spliterator<E> spliterator()
返回此队列中的元素Spliterator 。
Object[] toArray()
以适当的顺序返回一个包含此队列中所有元素的数组。
<T> T[] toArray(T[] a)
以适当的顺序返回包含此队列中所有元素的数组; 返回的数组的运行时类型是指定数组的运行时类型。
重要方法解读分析
- ArrayBlockingQueue(int capacity, boolean fair) 构造方法
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();
}
- put(E e)阻塞新增方法
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();
}
}
private void enqueue(E x) {
final Object[] items = this.items;
items[putIndex] = x;
if (++putIndex == items.length)
putIndex = 0;
count++;
notEmpty.signal();
}
- E take()
public E take() throws InterruptedException {
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
while (count == 0)
notEmpty.await();
return dequeue();
} finally {
lock.unlock();
}
}
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;
}
void elementDequeued() {
if (count == 0)
queueIsEmpty();
else if (takeIndex == 0)
takeIndexWrapped();
}