Java并发06:线程间通信 - wait/notify机制详解
引言:生产者-消费者问题 经典场景:生产者生产数据→放入队列→消费者从队列取数据。 问题: 队列满时,生产者如何等待? 队列空时,消费者如何等待? 如何通知对方继续工作? 这就是 wait/notify 机制要解决的问题。 一、wait/notify基础 1.1 三个核心方法 public class Object { // 释放锁,进入等待队列 public final void wait() throws InterruptedException {} // 释放锁,等待指定时间 public final void wait(long timeout) throws InterruptedException {} // 唤醒一个等待线程 public final void notify() {} // 唤醒所有等待线程 public final void notifyAll() {} } 关键约束:必须在 synchronized 块中调用! 1.2 工作原理 对象监视器(Monitor)结构 ┌─────────────────────────────────────┐ │ Object Monitor │ │ │ │ Entry Set(入口队列) │ │ ┌───────┐ ┌───────┐ │ │ │线程2 │ │线程3 │ ← BLOCKED │ │ └───────┘ └───────┘ │ │ ↓ │ │ ┌────────────┐ │ │ │ Owner │ ← RUNNABLE │ │ │ (线程1) │ │ │ └────────────┘ │ │ ↓ wait() │ │ Wait Set(等待队列) │ │ ┌───────┐ ┌───────┐ │ │ │线程4 │ │线程5 │ ← WAITING │ │ └───────┘ └───────┘ │ │ ↑ notify() │ └─────────────────────────────────────┘ 二、生产者-消费者实现 2.1 标准实现 class SharedQueue { private Queue<Integer> queue = new LinkedList<>(); private int capacity = 5; // 生产 public synchronized void produce(int value) throws InterruptedException { while (queue.size() == capacity) { // ← 用while,不是if System.out.println("队列满,生产者等待"); wait(); // 释放锁,进入等待 } queue.offer(value); System.out.println("生产: " + value); notifyAll(); // 唤醒消费者 } // 消费 public synchronized int consume() throws InterruptedException { while (queue.isEmpty()) { // ← 用while,不是if System.out.println("队列空,消费者等待"); wait(); } int value = queue.poll(); System.out.println("消费: " + value); notifyAll(); // 唤醒生产者 return value; } } 2.2 为什么用while不用if? // ❌ 错误:使用if if (queue.isEmpty()) { wait(); // 被唤醒后直接往下执行 } int value = queue.poll(); // ← 可能queue仍然为空! // ✅ 正确:使用while while (queue.isEmpty()) { wait(); // 被唤醒后重新检查条件 } int value = queue.poll(); // 确保queue不为空 原因:虚假唤醒(Spurious Wakeup) ...