Object.wait(long timeout)仅让线程在持有锁的前提下最多等待指定毫秒数,不自动处理超时逻辑,需配合synchronized、循环条件检查及状态变量实现可靠超时等待,且无法区分唤醒原因。

Java 中 Object.wait(long timeout) 方法本身不直接实现“超时后自动唤醒并继续执行”的完整逻辑,它只是让当前线程在对象监视器上等待最多指定毫秒数,之后可能被唤醒(无论是否超时),但**不会自动处理超时后的业务判断或重试**。要真正实现带有超时机制的等待逻辑,需要配合 synchronized、状态检查和循环等待(即所谓的“条件等待模式”)。
必须在 synchronized 块中调用 wait(timeout)
wait() 是 Object 的 final 方法,调用前线程必须持有该对象的锁,否则抛出 IllegalMonitorStateException。超时参数单位是毫秒,传 0 表示无限等待(等同于 wait())。
- 超时时间到,线程被系统唤醒,返回后仍需重新获取锁才能继续执行
- 即使超时,
wait()不会抛异常,也不会改变线程中断状态,需手动检查Thread.interrupted() - 被其他线程调用
notify()/notifyAll()唤醒时,也立即返回,不等满 timeout
典型用法:循环等待 + 条件检查
单纯调一次 wait(timeout) 很少够用。实际场景中,我们等待的是某个**条件成立**(如缓冲区非空、任务完成、标志位为 true),而非单纯“等一段时间”。因此标准写法是 while 循环 + 条件判断:
synchronized (lock) {
while (!conditionMet()) {
try {
lock.wait(5000); // 最多等 5 秒
} catch (InterruptedException e) {
Thread.currentThread().interrupt(); // 恢复中断状态
break;
}
}
// 此处 conditionMet() 为 true,或因超时/中断退出循环
}
注意:wait() 返回后必须再次检查条件,因为可能被虚假唤醒(spurious wakeup),也可能被 notify 但条件仍未满足。
立即学习“Java免费学习笔记(深入)”;
如何区分是超时还是被 notify 唤醒?
wait(timeout) 本身不提供唤醒原因的反馈。可靠方式是结合状态变量与时间戳:
- 记录进入等待前的系统时间(
System.currentTimeMillis()或System.nanoTime()) - 唤醒后计算已等待时间,若接近 timeout,大概率是超时;若远小于 timeout,更可能是被 notify
- 但最健壮的做法仍是依赖业务条件变量——例如设置
done = false,另一线程完成任务后设done = true并notify(),主逻辑只关心done是否为 true
常见误区与替代方案
直接用 wait(timeout) 当“延时工具”是错的(比如想停 100ms 再干活),应改用 Thread.sleep(100)。前者依赖锁和条件,后者只是让出 CPU。
-
wait()是协作式等待,必须配合notify()使用;sleep()是独占式休眠,无需同步 - JDK 5+ 更推荐使用
java.util.concurrent工具类,如LockSupport.parkNanos()、Condition.await(long, TimeUnit)或CountDownLatch.await(timeout),它们语义更清晰、支持中断、避免手写 synchronized 错误 - 如果只是等待某个异步结果,
CompletableFuture.get(timeout, unit)或Future.get(timeout, unit)更安全简洁


















