wait和notify是线程协作通信机制,必须在synchronized块中调用同一对象锁,因它们依赖对象监视器(Monitor)实现原子性释放锁+入等待队列或唤醒,定义在Object类是因锁属于对象而非线程。

直接说核心:wait 和 notify 是线程间协作的通信机制,不是锁控制工具,必须搭配 synchronized 使用,且调用对象必须是同一把锁。
为什么定义在 Object 类而不是 Thread 类?
因为通信依赖的是“对象监视器(Monitor)”,每个 Java 对象天然带一把锁,线程通过争抢对象锁进入临界区;wait/notify 的本质是让持有锁的线程主动释放并等待,或通知其他等待者——这个动作必须绑定到具体锁对象上。Thread 类代表执行单元,不承载锁语义,所以不能放在这里。
为什么必须在 synchronized 块里调用?
两个硬性原因:
- 调用前必须已获得该对象的 monitor 锁,否则抛 IllegalMonitorStateException
- wait() 的原子操作包含“释放锁 + 进入等待队列”,这两步必须不可分割;notify() 也需确保唤醒动作发生在锁保护的上下文中,避免竞态
wait() 和 notify() 的典型协作流程
以生产者-消费者为例:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
立即学习“Java免费学习笔记(深入)”;
- 消费者发现缓冲区为空 → 在 synchronized 块内调用 buffer.wait() → 释放 buffer 锁,进入等待队列
- 生产者往 buffer 加数据后 → 在 synchronized 块内调用 buffer.notify() → 唤醒一个等待线程(不立即释放锁)
- 被唤醒的消费者重新竞争 buffer 锁,拿到后继续执行(注意:要放在 while 循环里判断条件,防虚假唤醒)
notify() 和 notifyAll() 怎么选?
看等待线程是否“条件等价”:
- 如果所有等待线程都在等同一个条件(比如“缓冲区非空”),用 notifyAll() 更安全,避免漏唤醒
- 如果明确只有一个线程该被唤醒(如固定配对的请求-响应),可用 notify(),但需确保逻辑无歧义
- 实际开发中,除非性能敏感且逻辑绝对清晰,否则优先用 notifyAll()
常见踩坑点(面试官最爱追问)
这些答出来就能拉开差距:
- wait 写在 if 里 → 虚假唤醒导致逻辑错乱(必须用 while 检查条件)
- notify() 不保证唤醒哪个线程(JVM 随机选,不按等待先后)
- wait(0) 等价于 wait()(无限等待,直到被 notify 或中断)
- notify() 后当前线程仍持有锁,被唤醒线程要等它退出 synchronized 才能抢锁

















