基本概念
ArrayBlockingQueue
是一个基于数组的有界阻塞队列。它的主要特点包括:
- 有界队列:在创建
ArrayBlockingQueue
时,必须指定其容量。这个容量在队列的生命周期内是固定的。 - FIFO 顺序:元素按照先进先出的顺序进行处理。
- 阻塞操作:当队列为空时,获取元素的操作会被阻塞;当队列已满时,插入元素的操作会被阻塞。
- 线程安全:内部使用锁机制来保证线程安全。
构造函数
ArrayBlockingQueue
提供了三个构造函数:
// 创建一个具有指定容量的队列
ArrayBlockingQueue<E> queue = new ArrayBlockingQueue<>(int capacity);
// 创建一个具有指定容量和公平性的队列
ArrayBlockingQueue<E> queue = new ArrayBlockingQueue<>(int capacity, boolean fair);
// 创建一个具有指定容量、公平性并包含指定集合元素的队列
ArrayBlockingQueue<E> queue = new ArrayBlockingQueue<>(int capacity, boolean fair, Collection<? extends E> c);
主要方法
插入操作
boolean add(E e)
:如果队列满了,抛出IllegalStateException
。boolean offer(E e)
:如果队列满了,返回false
。void put(E e)
:如果队列满了,阻塞当前线程直到队列不满。boolean offer(E e, long timeout, TimeUnit unit)
:在指定时间内插入元素,如果队列满了,等待指定的时间。
移除操作
E remove()
:如果队列为空,抛出NoSuchElementException
。E poll()
:如果队列为空,返回null
。E take()
:如果队列为空,阻塞当前线程直到队列不空。E poll(long timeout, TimeUnit unit)
:在指定时间内移除元素,如果队列为空,等待指定的时间。
检查操作
E peek()
:返回队列头部的元素,但不移除。如果队列为空,返回null
。boolean contains(Object o)
:检查队列是否包含指定元素。
批量操作
int drainTo(Collection<? super E> c)
:移除队列中的所有可用元素,并将其添加到指定的集合中。int drainTo(Collection<? super E> c, int maxElements)
:最多移除maxElements
个元素,并将其添加到指定的集合中。
内部实现
ArrayBlockingQueue
使用一个数组来存储元素,并用两个指针 takeIndex
和 putIndex
来跟踪队列的头部和尾部。它还使用一个重入锁(ReentrantLock
)来保证线程安全,并结合两个条件变量(notEmpty
和 notFull
)来管理队列的阻塞操作。
使用示例
下面是一个具体的例子,展示了如何使用 ArrayBlockingQueue
进行插入和移除操作,并给出输出结果:
import java.util.concurrent.ArrayBlockingQueue;
public class Example {
public static void main(String[] args) {
ArrayBlockingQueue<Integer> queue = new ArrayBlockingQueue<>(3);
try {
// 插入元素
queue.put(1);
queue.put(2);
queue.put(3);
System.out.println("插入元素后队列: " + queue); // 输出: [1, 2, 3]
// 尝试插入第四个元素,会阻塞
Thread producer = new Thread(() -> {
try {
queue.put(4);
System.out.println("插入4成功: " + queue);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
producer.start();
// 移除元素
System.out.println("移除元素: " + queue.take()); // 输出: 1
System.out.println("移除元素后队列: " + queue); // 输出: [2, 3]
// 等待生产者线程插入第四个元素
producer.join();
System.out.println("最终队列: " + queue); // 输出: [2, 3, 4]
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
输出结果
插入元素后队列: [1, 2, 3]
移除元素: 1
移除元素后队列: [2, 3]
插入4成功: [2, 3, 4]
最终队列: [2, 3, 4]
优缺点
优点:
- 提供了线程安全的并发控制。
- 支持阻塞操作,适合生产者-消费者模型。
- 有界队列可以防止内存溢出。
缺点:
- 容量固定,不能动态调整大小。
- 在高并发场景下,锁机制可能会导致性能瓶颈。
总结
ArrayBlockingQueue
是一个功能强大且高效的并发数据结构,适用于需要在多线程环境中进行安全数据共享的场景。理解其内部机制和正确使用方法,可以帮助开发者更好地编写高性能的并发程序。