java中wait()必须与synchronized锁对象、条件状态、notify/notifyall三者统一:线程需先获得锁,条件判断用while循环防虚假唤醒,状态修改与notify须原子执行,wait释放锁,唤醒后需重新竞争锁并校验条件。

Java 中 wait() 方法必须和共享变量配合使用,但关键不在于“变量本身”,而在于用它作为同步锁和条件判断的载体。直接对共享变量调用 wait() 没有意义,真正起作用的是:该变量作为 synchronized 锁对象 + 条件状态的承载者 + wait()/notify() 的调用目标三者统一。
共享变量必须是 synchronized 锁的目标
调用 wait() 前,线程必须已持有该共享变量的监视器锁。否则会立即抛出 IllegalMonitorStateException。所以共享变量不能只是普通字段,而要被显式用作同步块的锁对象或同步方法的隐式锁:
- 推荐做法:声明一个专用的
private final Object lock = new Object();,所有同步和wait/notify都围绕它展开 - 也可复用业务对象(如
queue、flag),但需确保所有相关操作都用它加锁,避免锁对象不一致 - 绝对不要用
this或易变对象(如可变集合引用)作锁,容易引发死锁或通知失效
共享变量承载线程等待的业务条件
wait 不是无条件挂起,而是等待某个状态成立。这个状态就存放在共享变量中,比如:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 缓冲区是否为空(
queue.isEmpty()) - 标志位是否切换(
flag.equals("A")) - 计数器是否达标(
count )
这些判断必须写在 while 循环里,不能用 if —— 因为即使没被 notify,线程也可能被虚假唤醒,必须重新校验条件是否真正满足。
notify 必须在修改共享变量后、同一锁内执行
唤醒动作和状态变更必须原子化。典型流程是:
- 获取锁 → 检查条件 → 修改共享变量(如
queue.add(item)或flag = "B")→ 调用notify()或notifyAll()→ 退出同步块 - 如果先
notify()再改状态,可能唤醒的线程看到旧值,再次进入 wait,造成“通知丢失” - 用
notifyAll()更稳妥,尤其当多个线程等待不同子条件时(如生产者/消费者共用同一锁)
wait 会释放锁,被唤醒后需重新竞争
调用 wait() 的瞬间,线程释放当前持有的锁,进入该对象的等待队列。被 notify() 唤醒后,它不会立刻执行,而是回到同步队列,和其他线程一起竞争该锁。只有抢到锁,才能从 wait() 返回,继续执行后续逻辑。因此:
- 不能假设唤醒后条件一定成立,必须在
while循环中再次检查 - 同步块结束时锁自动释放,无需手动干预
- 若在
wait()期间被中断,会抛InterruptedException,应合理处理(如清理资源、退出循环)
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










