✅ 1. 作用一句话
- notify() 随机唤醒一个正在
wait()
的线程。
- notifyAll() 唤醒所有正在
wait()
的线程,让它们竞争锁。
✅ 2. 使用前提(铁律)
- 必须在 同步块/方法 内调用:
synchronized (lock) {
lock.notify(); // 或 notifyAll();
}
- 调用者必须持有锁,否则会抛
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
循环检查条件。”