wait()释放锁而sleep()不释放锁,前者用于线程协作需synchronized配合notify(),后者仅为线程暂停且独立于锁机制。

wait() 会释放锁,sleep() 不会 —— 这是所有行为差异的起点
很多线程问题卡在“为什么 notify() 没唤醒线程”或“死锁时线程明明醒了却卡住”,根源常是误以为 sleep() 也能让出锁。不是的:wait() 必须在 synchronized 块里调用,一执行就立刻释放当前对象锁;sleep() 是 Thread 类的静态方法,只暂停当前线程,锁照常攥着。
常见错误现象:
- 在非
synchronized方法里调用wait()→ 抛IllegalMonitorStateException - 用
sleep(1000)替代wait()等待条件变量 → 其他线程无法通过notify()提前唤醒它,只能硬等满时长 - 多个线程竞争同一把锁,其中一个调了
sleep(),其余线程仍被阻塞 → 因为锁没释放
wait() 必须配合 notify()/notifyAll() 使用,sleep() 完全独立
wait() 的设计目标是“等某个条件成立”,所以它不接受超时参数(除非用带参重载),也不负责决定何时继续;它只管挂起,靠别人喊它。而 sleep() 就是“我歇会儿”,时间一到自动醒,不依赖外部协作。
使用场景差异:
立即学习“Java免费学习笔记(深入)”;
- 生产者-消费者模型中,缓冲区空时消费者该调
wait(),等生产者notify();绝不能用sleep()轮询,浪费 CPU 且实时性差 - 需要固定延迟(比如每 5 秒发一次心跳),直接用
Thread.sleep(5000),别扯锁和notify() -
wait(long timeout)虽有超时,但仍是等待条件 + 防死等的组合策略,不是替代sleep()的方案
中断响应方式不同:sleep() 直接抛 InterruptedException,wait() 清除中断状态后才抛
这是最容易踩的坑:如果线程在 wait() 中被中断,它会先清除当前线程的中断标志(即 Thread.interrupted() 返回 true 后变 false),再抛出 InterruptedException;而 sleep() 抛异常前不碰中断状态。
后果很实际:
- 在
wait()的 catch 块里直接忽略异常,可能导致后续逻辑永远收不到中断信号(因为标志已被清掉) - 正确做法是在
wait()的 catch 中手动重设中断状态:Thread.currentThread().interrupt(); -
sleep()的中断处理更直白:catch 住就完事,无需额外补操作
它们根本不在一个抽象层级上 —— 别拿“都让线程停一会儿”去类比
wait() 属于线程间协作机制,绑定对象监视器(monitor),是 Java 并发模型里“等待-通知”范式的基石;sleep() 只是操作系统线程调度层面的暂停指令,和锁、通信完全无关。
性能与兼容性影响:
- 频繁调用
wait()/notify()本身开销不大,但若唤醒逻辑写错(比如 notify() 发给错的对象),会导致线程永久挂起,极难调试 -
sleep()在不同 JVM 实现下精度可能有偏差(尤其 Windows 上最小粒度约 15ms),但行为稳定;wait()的唤醒时机还受 JVM 线程调度策略和 GC 暂停影响 - JDK 9+ 中
Thread.sleep()支持纳秒级参数,但实际精度仍受限于系统;wait()的纳秒参数同理,别指望真能控制到纳秒级唤醒
最常被忽略的一点:你写的 wait() 代码,大概率跑在某个对象实例上;而 sleep() 永远作用于当前线程本身——这个主语差异,决定了它们根本不能互相替换。










