✅ 1. 作用一句话

  • notify() 随机唤醒一个正在 wait() 的线程。
  • notifyAll() 唤醒所有正在 wait() 的线程,让它们竞争锁。

✅ 2. 使用前提(铁律)

  1. 必须在 同步块/方法 内调用:
    synchronized (lock) {
        lock.notify();      // 或 notifyAll();
    }
    
  2. 调用者必须持有锁,否则会抛 IllegalMonitorStateException

✅ 3. 工作流程(notify 为例)

Thread-A 获得锁
    ↓ 发现条件不满足
    ↓ lock.wait() 释放锁并阻塞
Thread-B 获得锁
    ↓ 修改条件
    ↓ lock.notify() 唤醒 Thread-A(仍阻塞)
Thread-B 退出同步块 释放锁
Thread-A 重新竞争锁 → 竞争到后从 wait() 之后继续执行

✅ 4. 二者差异对照表

维度 notify() notifyAll()
唤醒数量 1 个(任意选择) 所有等待线程
风险 可能“信号丢失”(被唤醒线程再次 wait) 不会丢失,但带来竞争
适用场景 单消费者模型(如线程池任务) 多生产者/多消费者模型
性能 较低竞争 较高竞争(所有线程都醒来抢锁)

✅ 5. 经典生产-消费示例(notifyAll)

class Buffer {
    private final Queue<Integer> q = new LinkedList<>();
    private final int MAX = 3;

    public void put(int val) throws InterruptedException {
        synchronized (this) {
            while (q.size() == MAX) wait();   // 满则等待
            q.offer(val);
            notifyAll();                      // 唤醒所有等待线程(可能有空位)
        }
    }

    public int take() throws InterruptedException {
        synchronized (this) {
            while (q.isEmpty()) wait();       // 空则等待
            int v = q.poll();
            notifyAll();                      // 唤醒所有等待线程(可能有数据)
            return v;
        }
    }
}

✅ 6. 高频坑点

错误示例 后果
wait() 之前未检查条件(用 if 而非 while 虚假唤醒导致逻辑错误
调用 notify() 时无等待线程 信号丢失
同步块外 调用 notify() IllegalMonitorStateException

✅ 7. 面试金句

wait/notify 是 Java 最底层线程通信机制;notifyAll 更安全,notify 更高效,但必须配合 while 循环检查条件。”