notify必须在synchronized块内调用且锁对象一致,作用是唤醒同一锁上waiting状态的线程;需与wait成对使用、用while循环校验条件,并根据业务语义选择notify或notifyall。

notify 方法不能单独使用,必须和 synchronized 配合,否则会直接抛出 IllegalMonitorStateException。它的作用不是“唤醒任意线程”,而是唤醒在同一个锁对象上处于 WAITING 状态的线程——前提是这个线程之前调用了 wait() 并已释放锁。
必须在 synchronized 块内调用,且锁对象一致
notify 操作的是 JVM 中该对象的监视器(monitor),调用前当前线程必须已持有该对象的锁。否则 JVM 会拒绝执行。
- ✅ 正确:synchronized(lock) { lock.notify(); }
- ❌ 错误:synchronized(obj1) { obj2.notify(); } —— 锁对象和 notify 对象不匹配
- ⚠️ 不推荐:直接用 this.notify() —— 外部可能意外同步 this,导致干扰或死锁
- 推荐声明 private final Object lock = new Object();,专用于线程协作
notify 必须和 wait 成对出现在同一把锁下
wait() 会让线程释放锁、进入 WAITING 状态并加入该对象的等待队列;notify() 则从这个等待队列中选一个线程移入入口队列,等它重新竞争到锁后才能继续执行。
- wait 和 notify 必须作用于同一个对象实例(即同一 monitor)
- 一个线程 wait 后,只有其他线程在同锁下调用 notify 或 notifyAll 才能将其唤醒
- BLOCKED 状态的线程(比如抢锁失败)不会被 notify 影响——它压根不在等待队列里
状态修改与通知必须原子化,且条件要用 while 循环校验
notify 本身不保证条件成立,它只是“发个信号”。真正安全的协作依赖三件事:状态更新、通知、条件重检,全部在锁保护下完成。
- 先改共享状态(如 queue.add(item)),再 notify(),且都在 synchronized 块内
- 等待方必须用 while 而非 if:while (!condition) { lock.wait(); },防止虚假唤醒
- 被唤醒的线程重新获取锁后,第一件事仍是检查条件是否真满足,再执行后续逻辑
notify 和 notifyAll 的选择取决于业务语义
notify 只唤醒一个线程,notifyAll 唤醒全部等待者。选错会导致部分线程永远等不到信号,或引发不必要的竞争。
- 用 notify():多个线程等待同一类资源,且唤醒任意一个即可(如连接池取空闲连接)
- 用 notifyAll():不同线程等待不同条件(如有的等“数据就绪”,有的等“配置加载完成”),或需广播状态变更(如关闭标志位)
- 注意:notify() 唤醒后若条件仍不满足,线程会再次 wait()——这是设计使然,不是 bug
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











