线程的sleep和wait有什么区别?sleep和wait的操作过程中可以打断吗?
2025/12/30大约 4 分钟面试题面试题
1. 面试官为什么爱问这个?
这题看似基础,其实暗藏杀机。很多人只会背 API 区别表,但面试官更想听到:
- 你对 线程调度 和 锁机制 的理解
- 你在 真实业务场景 下的选型思路
- 你对 异常与中断 的处理经验
2. 从语义上看本质区别
Thread.sleep():让当前线程 “暂停执行” 一段时间,不释放锁。相当于你在会议室占着座位玩手机,不去开会,但座位还是你的。Object.wait():让当前线程释放对象锁并进入等待状态,直到被唤醒或超时。相当于你把会议室钥匙交给前台,自己去休息室等,别人可以用会议室。
3. 标准对比表(背下来是基本功)
对比维度sleep(long)wait()
** / **wait(long)
所属类java.lang.Thread
(静态方法)java.lang.Object
(实例方法)
调用位置
任意位置
必须在 synchronized
代码块 / 方法中
是否释放锁
❌ 不释放
✅ 释放对象监视器锁
唤醒方式
时间到自动唤醒 / 被打断notify()
/notifyAll()
/ 被打断 / 超时
用途
延时执行、降低 CPU 占用
线程间通信、条件等待
是否可中断
✅ 可被 interrupt()
打断
✅ 可被 interrupt()
打断
4. 中断机制的细节
很多人只知道 “可以打断”,但细节才是面试官的陷阱:
4.1 sleep() 被打断
- 在睡眠中调用
interrupt()会抛出InterruptedException - 抛出异常后,中断状态会被清除(
Thread.interrupted()返回 false)
Thread t = new Thread(() -> {
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
System.out.println("sleep被打断");
System.out.println("中断状态: " + Thread.currentThread().isInterrupted()); // false
}
});
t.start();
t.interrupt();4.2 wait() 被打断
- 同样会抛出
InterruptedException - 同样会清除中断状态
- 但
wait()还可能遭遇 虚假唤醒(spurious wakeup),必须在循环中检查条件
synchronized (lock) {
while (!condition) {
lock.wait();
}
}5. 底层实现差异(进阶)
sleep():是Thread的静态 native 方法,由 JVM 调度器直接挂起线程,不涉及锁释放。wait():是Object的方法,必须持有对象监视器(monitor),调用后释放 monitor 并进入条件队列,被唤醒后重新竞争锁。
6. 真实业务场景
6.1 使用 sleep() 的场景
- 模拟重试机制:比如调用第三方 API 失败后,等待 1 秒再重试
- 限流:在循环中
sleep控制 QPS - 测试延迟:单元测试中模拟网络延迟
示例:
for (int i = 0; i < 3; i++) {
try {
if (callThirdPartyAPI()) break;
Thread.sleep(1000); // 等一秒再重试
} catch (InterruptedException e) {
Thread.currentThread().interrupt(); // 重新设置中断状态
break;
}
}6.2 使用 wait() 的场景
- 生产者 - 消费者模型:队列空时消费者等待,有数据时被唤醒
- 条件等待:订单支付成功后,唤醒等待发货的线程
- 连接池:获取连接时,如果池为空则等待
示例:
synchronized (queue) {
while (queue.isEmpty()) {
queue.wait(); // 队列空,等待
}
return queue.poll();
}7. 面试官可能追问的点
- 为什么
wait()必须在同步块中调用?
- 因为需要先获取对象锁,才能释放锁进入等待状态。
sleep(0)** 有什么用?**
- 触发线程重新调度,让同等优先级的线程有机会运行。
interrupt()** 后,线程状态如何变化?**
sleep/wait状态 → 抛出异常 → 变为Runnable。
- 虚假唤醒如何处理?
- 永远在
while循环中检查条件,而不是if。
8. 总结口诀
sleep** 占着茅坑睡觉,wait 把茅坑让出来等人叫。**两者都能被打断,但 wait 必须在同步块中,且要防虚假唤醒。