【Java 并发面试】Thread.sleep vs Object.wait:都是“暂停”,凭什么你就要释放锁?
面试官:sleep 和 wait 都能暂停线程,凭什么你就要释放锁?
“sleep和 wait都能让线程停下来,它俩到底有啥区别?”
如果你只回答:“一个是 Thread 类的方法,一个是 Object 类的方法”,那面试官大概率会觉得你只是背了八股文,并没有理解并发的核心。
今天咱们用**“占坑”**的例子,一次性把这两个方法的底层逻辑讲透。以后再被问到,直接把这个场景甩给面试官。
一、 核心区别:关键在于“锁” (Lock)
这是最最最核心的区别,请刻在 DNA 里:
-
sleep (睡觉):是自私的。线程虽然停下来休息了,但是它手里的锁(Key)是不释放的。
-
潜台词:“我睡一会,但我占着茅坑不拉屎,外面的兄弟谁也别想进来。”
-
-
wait (等待):是无私的(或者说是被迫无奈)。线程停下来,会主动释放锁,进入等待队列。
-
潜台词:“哎呀,我需要的条件(比如数据)还没准备好,我先把坑位让出来,你们先用,等条件好了(notify)再叫我。”
-
场景模拟:试衣间
假设有一个试衣间(锁/Monitor),只有一把钥匙。
-
sleep 的场景:
你拿着钥匙进了试衣间,锁上门。突然你想休息 5 分钟。于是你在里面睡着了。
-
后果:外面排队的人(其他线程)急死了,因为门是锁着的,谁也进不来。时间到了你自己醒了,继续试衣服,试完才出门。
-
-
wait 的场景:
你拿着钥匙进了试衣间,锁上门。发现衣服尺码不对(条件不满足)。
-
后果:你不能干占着位置啊。于是你开锁,走出门,坐在门口的小板凳上等(Wait Set)。这时候,别人(其他线程)就可以拿钥匙进试衣间了。等店员(另一个线程)拿来了新衣服,喊了一声“衣服到啦”(notify),你再去重新排队抢钥匙进门。
-
二、 来源不同:为什么 wait 定义在 Object 里?
这也是个经典追问。
-
Thread.sleep():它是
Thread类的静态方法。-
它是用来控制当前正在执行的线程的。它不需要依赖任何锁(Monitor),就是单纯的“让 CPU 休息一会”。
-
-
Object.wait():它是
Object类的成员方法。-
为什么不是 Thread 的方法? 因为 Java 中的锁(Monitor)是绑定在对象上的!
-
当你调用
lock.wait()时,你是在操作这个lock对象上的等待队列。为了让任何对象都能成为锁,这个方法必须定义在基类Object中。
-
三、 使用限制:要不要 try-catch?要不要 synchronized?
1. 异常处理 (InterruptedException)
俩人都一样。不管是睡着了还是在等待,如果有人想暴力唤醒你(调用 interrupt()),它俩都会抛出 InterruptedException。所以都需要 try-catch。
2. 同步代码块 (Synchronized)
-
sleep:不需要。你想在哪睡就在哪睡,可以在客厅(同步块外),也可以在卧室(同步块内)。
-
wait:必须在 synchronized 块中调用。
-
为什么? 回到第一点,
wait的前提是“释放锁”。如果你手里连锁都没有,你释放个寂寞? -
如果不加
synchronized直接调用wait,会抛出IllegalMonitorStateException(非法监视器状态异常)。
-
四、 唤醒机制:谁来叫醒我?
-
sleep(long millis):自动醒。
-
你是定闹钟睡觉的。时间到了(比如 1000ms),你就会自动醒来,重新去抢 CPU 时间片。
-
-
wait():被动醒(如果不传超时时间)。
-
你是“死等”。除非有别的线程调用了同一个锁对象的
notify()或notifyAll(),否则你会一直等到天荒地老。 -
注:
wait(long timeout)也可以设置超时自动醒,这点和 sleep 类似,但它依然需要先获取锁。
-
总结:一张表看懂
| 特性 | Thread.sleep() | Object.wait() |
| 所属类 | Thread |
Object |
| 对锁的处理 | 抱着锁睡觉(不释放) | 放下锁等待(释放锁) |
| 使用范围 | 任何地方 | 必须在 synchronized 块内 |
| 唤醒方式 | 时间到自动醒 | 需要 notify() / notifyAll() |
| 核心用途 | 模拟延迟、暂停执行 | 线程间通信(生产/消费) |
最后的实战建议
-
如果你只是想让程序“卡”一下,比如轮询的时候防止 CPU 空转,或者模拟网络延迟,请用
sleep。 -
如果你是做线程间通信,比如“生产者-消费者”模型,队列满了生产者要等,队列空了消费者要等,必须用
wait/notify(或者更高级的Condition.await/signal)。
以后面试官再问,记住那句话:Sleep 是自私的占坑,Wait 是无私的让位。

更多推荐



所有评论(0)