介绍

ArrayBlockingQueue 是 Java 并发包 (java.util.concurrent) 中的一个线程安全的阻塞队列实现。它基于数组实现,具有固定的容量,支持多线程环境下的高效生产和消费操作。

特性

  • 有界队列ArrayBlockingQueue 是一个有界队列,容量在创建时固定,无法动态扩容。
  • 线程安全:内部通过 ReentrantLock 实现线程安全。
  • 阻塞操作
    • 当队列满时,插入操作会被阻塞,直到队列有空闲空间。
    • 当队列空时,取出操作会被阻塞,直到队列中有新元素。

方法

  • 插入操作
    • add(E e):插入元素,如果队列满则抛出异常。
    • offer(E e):插入元素,如果队列满则返回 false
    • put(E e):插入元素,如果队列满则阻塞等待。
  • 取出操作
    • remove():取出并移除队头元素,如果队列空则抛出异常。
    • poll():取出并移除队头元素,如果队列空则返回 null
    • take():取出并移除队头元素,如果队列空则阻塞等待。
  • 检查操作
    • element():获取队头元素但不移除,如果队列空则抛出异常。
    • peek():获取队头元素但不移除,如果队列空则返回 null

原理

数据结构

  • ArrayBlockingQueue内部使用一个定长数组 (Object[]) 存储元素。
  • 通过两个指针 (takeIndexputIndex) 分别指向队头和队尾。

线程安全

  • 使用 ReentrantLock 保证线程安全。
  • 通过两个条件变量 (notEmptynotFull) 实现阻塞操作:
    • notEmpty:当队列为空时,消费者线程等待。
    • notFull:当队列满时,生产者线程等待。

核心方法实现

put(E e)

1
2
3
4
5
6
7
8
9
10
11
12
13
public void put(E e) throws InterruptedException {
Objects.requireNonNull(e);
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
while (count == items.length) {
notFull.await(); // 队列满时阻塞
}
enqueue(e); // 入队
} finally {
lock.unlock();
}
}

take()

1
2
3
4
5
6
7
8
9
10
11
12
public E take() throws InterruptedException {
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
while (count == 0) {
notEmpty.await(); // 队列空时阻塞
}
return dequeue(); // 出队
} finally {
lock.unlock();
}
}

优缺点

优点
  • 线程安全:内置锁机制,支持多线程并发操作。
  • 阻塞操作:支持生产者和消费者的阻塞等待,简化了线程间协作。
  • 性能较高:基于数组实现,访问效率高。

缺点
  • 固定容量:队列容量固定,无法动态扩容。
  • 锁竞争:在高并发场景下,锁竞争可能成为性能瓶颈。