wait方法仅实现线程挂起与协作等待,不终止线程;其必须在synchronized中调用,释放锁并进入waiting状态,待notify/notifyall唤醒或中断后重新竞争锁,配合volatile标志、while循环校验条件及interruptedexception处理方可实现优雅退出。

wait 方法本身不负责线程退出,它只用于线程间协作等待;优雅退出需配合中断机制、状态标志和 notify/notifyAll 使用。
wait 的本质是释放锁并挂起当前线程
调用 wait() 必须在 synchronized 块或方法中执行,它会让当前线程释放对象监视器(锁),进入 WAITING 状态,直到被其他线程调用 notify() 或 notifyAll() 唤醒,或被中断。它不是“退出”线程,而是“暂停执行、等待条件变化”。
- 不能单独靠 wait 实现退出——它不改变线程生命周期状态(RUNNABLE → WAITING,而非 TERMINATED)
- 唤醒后线程会重新竞争锁,获得锁后才从 wait 返回,继续执行后续代码
- 必须配合 while 循环检查条件,防止虚假唤醒(spurious wakeup)
结合 volatile 标志位实现可控退出
用一个 volatile 布尔变量作为“运行开关”,让等待中的线程能感知外部终止请求:
public class GracefulStop {
private final Object lock = new Object();
private volatile boolean running = true;
public void waitForSignal() throws InterruptedException {
synchronized (lock) {
while (running && !shouldProceed()) {
lock.wait(); // 等待条件满足或被唤醒
}
}
}
public void stop() {
running = false;
synchronized (lock) {
lock.notifyAll(); // 唤醒所有等待者,让它们检查 running 状态
}
}
private boolean shouldProceed() {
// 实际业务条件判断,例如队列非空、任务就绪等
return false;
}
}
-
volatile保证 running 修改对所有线程可见 - wait 外层用
while而非if,确保唤醒后再次校验退出条件 -
stop()中先改标志再 notify,避免唤醒后立即又进入 wait
响应中断实现真正“优雅”的退出
Java 线程中断机制是标准退出信号。wait 会响应 Thread.interrupt() 并抛出 InterruptedException,此时应清理资源、退出循环:
Java JDK 25 来自 OpenJDK 官方归档,版本为 JDK 25,本条下载地址已指向官方 Windows x64 zip 安装包直链,适合调试旧项目或兼容旧版 Java 运行环境。
- 捕获 InterruptedException 后通常应恢复中断状态:
Thread.currentThread().interrupt(); - 不要忽略该异常,也不要仅打印日志后继续等待——这会阻塞退出
- 可将中断作为退出依据,与标志位结合使用,增强鲁棒性
例如:
synchronized (lock) {
while (running && !ready) {
try {
lock.wait();
} catch (InterruptedException e) {
Thread.currentThread().interrupt(); // 恢复中断标记
return; // 主动退出等待逻辑
}
}
}
notify 与 notifyAll 的选择影响同步可靠性
唤醒操作决定哪些等待线程能继续执行:
-
notify()只唤醒一个线程,适合“单生产者-单消费者”且条件唯一场景,但易导致某些线程永远等待(signal loss) -
notifyAll()唤醒所有等待线程,各自重新检查条件,更安全,推荐用于多数场景 - 务必在 synchronized 块内调用 notify/notifyAll,否则抛出 IllegalMonitorStateException
注意:唤醒不等于立即执行——被唤醒线程需重新获取锁后才能继续,因此业务逻辑中不应假设唤醒即刻生效。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










