Java中使用BlockingQueue实现生产者-消费者模型,核心是利用put()/take()等阻塞方法自动处理线程同步与等待,推荐ArrayBlockingQueue、LinkedBlockingQueue或SynchronousQueue,并需妥善处理中断与优雅关闭。

Java 中使用 Queue 接口实现生产者-消费者模型,核心在于选择线程安全的队列实现(如 BlockingQueue 子类),配合 put() 和 take() 等阻塞方法,避免手动加锁和等待/通知逻辑。
选用合适的线程安全队列
Queue 本身是接口,不能直接实例化。生产者-消费者场景必须用线程安全的实现,推荐 ArrayBlockingQueue、LinkedBlockingQueue 或 SynchronousQueue:
-
ArrayBlockingQueue:有界、基于数组、公平可选,适合对内存和吞吐量有明确约束的场景 -
LinkedBlockingQueue:默认无界(实际为Integer.MAX_VALUE),基于链表,吞吐量通常更高 -
SynchronousQueue:不存储元素,每个put()必须等待匹配的take(),适合高实时性、零缓冲的传递场景
定义生产者与消费者任务
生产者调用 queue.put(item)(阻塞直到有空位),消费者调用 queue.take()(阻塞直到有元素)。两者都应放在独立线程中运行:
- 生产者线程循环生成数据,调用
put()入队;若队列满,自动阻塞,无需wait() - 消费者线程循环调用
take()出队并处理;若队列空,自动阻塞,无需notify() - 建议配合
ExecutorService管理线程,避免手动创建和销毁线程
处理中断与优雅关闭
阻塞操作响应中断信号,因此需在循环中捕获 InterruptedException 并恢复中断状态:
立即学习“Java免费学习笔记(深入)”;
- 生产者或消费者中遇到
InterruptedException时,应调用Thread.currentThread().interrupt() - 关闭时可调用
executor.shutdown()+awaitTermination(),或向队列添加特殊“结束标记”(如null或自定义哨兵对象) - 避免在
put/take外层用while(true)无限循环,应结合退出条件(如计数器、关闭标志)
一个最小可运行示例
以下代码演示单生产者、单消费者使用 LinkedBlockingQueue:
<font size="2"><pre class="brush:php;toolbar:false;">BlockingQueue<String> queue = new LinkedBlockingQueue<>(10);<br><br>// 生产者<br>new Thread(() -> {<br> try {<br> for (int i = 0; i < 5; i++) {<br> String msg = "item-" + i;<br> System.out.println("Producing: " + msg);<br> queue.put(msg); // 阻塞直到入队成功<br> Thread.sleep(100);<br> }<br> } catch (InterruptedException e) {<br> Thread.currentThread().interrupt();<br> }<br>}).start();<br><br>// 消费者<br>new Thread(() -> {<br> try {<br> for (int i = 0; i < 5; i++) {<br> String msg = queue.take(); // 阻塞直到取到元素<br> System.out.println("Consuming: " + msg);<br> }<br> } catch (InterruptedException e) {<br> Thread.currentThread().interrupt();<br> }<br>}).start();


















