在 JavaSE 的多线程编程中,阻塞队列(BlockingQueue) 是一种非常常用的线程通信机制,广泛应用于生产者-消费者模型中。下面是完整详尽的讲解,适合初学者与进阶开发者理解。


🧭 目录

  1. 什么是阻塞队列?
  2. 阻塞队列的工作原理
  3. Java 提供的阻塞队列接口与实现类
  4. 核心方法介绍
  5. 使用示例:生产者-消费者模型
  6. 常见面试题总结
  7. 延伸阅读

1️⃣ 什么是阻塞队列?

阻塞队列(BlockingQueue)是一个支持两个附加操作的队列:

  • 在队列为空时,获取元素的线程会等待队列变为非空。
  • 在队列满时,插入元素的线程会等待队列可用。

它是 Java 并发包 java.util.concurrent 中的接口,用于实现线程安全的队列通信


2️⃣ 阻塞队列的工作原理

阻塞队列内部通过 锁机制(Lock) 和 条件变量(Condition) 控制线程的等待与唤醒。

两种阻塞情况:

  • take() 阻塞:当队列为空,线程阻塞直到有元素可取;
  • put() 阻塞:当队列满,线程阻塞直到有空位可放入新元素。

这使得阻塞队列非常适合用于线程生产/消费不同步的情况。


3️⃣ Java 提供的阻塞队列接口与实现类

实现类特点
ArrayBlockingQueue基于数组的有界阻塞队列
LinkedBlockingQueue基于链表的可选边界阻塞队列(默认大小为 Integer.MAX_VALUE)
PriorityBlockingQueue支持优先级排序的无界阻塞队列
DelayQueue只有到期元素才能被取出的延迟队列
SynchronousQueue不存储元素,每个 put 必须等待 take
LinkedTransferQueue支持生产者直接把数据传给消费者
LinkedBlockingDeque双端阻塞队列

4️⃣ 核心方法介绍(以 BlockingQueue 接口为例)

方法说明
boolean add(E e)插入元素,失败抛异常
boolean offer(E e)插入元素,失败返回 false
void put(E e)插入元素,队列满时阻塞
boolean offer(E e, long timeout, TimeUnit unit)插入元素,超时等待
E take()获取并移除头部元素,队列为空时阻塞
E poll(long timeout, TimeUnit unit)获取并移除头部元素,等待时间
E peek()仅查看头部元素,不移除

5️⃣ 使用示例:生产者-消费者模型

示例代码(使用 LinkedBlockingQueue):

import java.util.concurrent.*;

public class BlockingQueueDemo {

    public static void main(String[] args) {
        BlockingQueue<String> queue = new LinkedBlockingQueue<>(5);

        // 生产者线程
        new Thread(() -> {
            try {
                for (int i = 0; i < 10; i++) {
                    queue.put("商品" + i);
                    System.out.println("生产:商品" + i);
                    Thread.sleep(300);
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }).start();

        // 消费者线程
        new Thread(() -> {
            try {
                while (true) {
                    String item = queue.take();
                    System.out.println("消费:" + item);
                    Thread.sleep(500);
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }).start();
    }
}

输出样例:

生产:商品0
消费:商品0
生产:商品1
...

6️⃣ 常见面试题总结

问题解答简要
BlockingQueue 和 Queue 有何区别?前者支持阻塞操作,适合并发环境。
SynchronousQueue 有什么特别之处?不存储元素,适合高并发交换数据。
如何实现延迟队列?使用 DelayQueue,元素需实现 Delayed 接口。
ArrayBlockingQueue 和 LinkedBlockingQueue 有什么不同?前者数组结构,后者链表结构;默认容量不同。

🔚 7️⃣ 延伸阅读


如需我帮您制作这套内容的图解版、PPT 教案版、简体/繁体版本、或者其他实战例子(如线程池中配合使用 BlockingQueue),欢迎继续提问!