生产者-消费者:生产 A/B/C 共 300 个,4 个消费者随机消费(每类消费各 100)?
> 要点:**一个生产者**随机打乱 300 条消息(A/B/C 各 100)放入**阻塞队列**;**四个消费者**并发从队列消费;用原子计数统计 A/B/C 各消费到 100;最后用**毒丸**优雅停机。也可用锁 + 条件变量版本(下方附带)。
1 个回答
优先考虑那些先考虑你的人慕骨天尊## 代码(BlockingQueue 版本,简单稳定) ```java import java.util.*; import java.util.concurrent.*; import java.util.concurrent.atomic.AtomicInteger; public class ProdConsABC { enum Type { A, B, C } static class Msg { final Type type; final int id; Msg(Type t, int id){ this.type=t; this.id=id; } } static final Msg POISON = new Msg(null, -1); public static void main(String[] args) throws Exception { LinkedBlockingQueue<Msg> q = new LinkedBlockingQueue<>(1000); AtomicInteger aCnt = new AtomicInteger(), bCnt = new AtomicInteger(), cCnt = new AtomicInteger(); // 1) 生产者:A/B/C 各 100,打乱后入队 Thread producer = new Thread(() -> { try { List<Msg> all = new ArrayList<>(300); int id = 1; for (int i=0;i<100;i++) all.add(new Msg(Type.A, id++)); for (int i=0;i<100;i++) all.add(new Msg(Type.B, id++)); for (int i=0;i<100;i++) all.add(new Msg(Type.C, id++)); Collections.shuffle(all); for (Msg m : all) q.put(m); // 投递 4 个毒丸,方便 4 个消费者退出 for (int i=0;i<4;i++) q.put(POISON); } catch (InterruptedException ignored) {} }, "producer"); // 2) 四个消费者:随机并发消费 Runnable consumerTask = () -> { try { while (true) { Msg m = q.take(); if (m == POISON) { // 毒丸:让下一个也能收到 q.put(POISON); break; } switch (m.type) { case A -> aCnt.incrementAndGet(); case B -> bCnt.incrementAndGet(); case C -> cCnt.incrementAndGet(); } // 模拟处理 // Thread.sleep(ThreadLocalRandom.current().nextInt(2)); } } catch (InterruptedException ignored) {} }; List<Thread> consumers = new ArrayList<>(); for (int i=0;i<4;i++) { Thread t = new Thread(consumerTask, "consumer-"+i); consumers.add(t); } producer.start(); consumers.forEach(Thread::start); producer.join(); for (Thread t : consumers) t.join(); System.out.printf("A=%d, B=%d, C=%d, total=%d%n", aCnt.get(), bCnt.get(), cCnt.get(), aCnt.get()+bCnt.get()+cCnt.get()); // 期望:A/B/C 各 100 } } ``` ### 可选:锁 + 条件变量版本(更贴近“队列+锁”考点) * 自己实现一个**有界缓冲区**(数组环形缓冲); * 用 `ReentrantLock` + `notEmpty`/`notFull` 两个 `Condition`; * `put`/`take` 时在条件不满足时 `await`,满足时 `signal` 对方队列。 > 面试时把两种写法思路讲清楚即可,BlockingQueue 生产上更安全省心。 **易错点** * 退出条件:不要让消费者阻塞在空队列;用“**毒丸**”或共享 `stop` 标记; * 统计并发安全:用 `AtomicInteger`; * 队列要**有界**避免 OOM; * 随机消费“公平性”不保证,但总量上 A/B/C 各 100 可以由**生产端**保证(如上)。发布于 2025-08-15 07:07 •IP属地 江苏举报评论收藏
公众号进入网站体验更佳

