一、一句话先记住(非常重要)
sleep 是 Thread 的"休息",不释放锁;
wait 是 Object 的"等待通知",会释放锁。

二、sleep vs wait 对比表(核心差异)
| 对比点 | sleep() |
wait() |
|---|---|---|
| 所属类 | Thread |
Object |
| 是否释放锁 | ❌ 不释放 | ✅ 释放 |
| 使用位置 | 任意地方 | 必须在 synchronized 中 |
| 唤醒方式 | 时间到自动醒 | notify / notifyAll |
| 是否需要捕获异常 | 是(InterruptedException) | 是 |
| 用途 | 让线程暂停一段时间 | 线程间通信 |
三、代码对比 ①:sleep 不释放锁
示例:sleep 导致别的线程进不来
java
public class SleepDemo {
private static final Object lock = new Object();
public static void main(String[] args) {
new Thread(() -> {
synchronized (lock) {
System.out.println("线程A拿到锁");
try {
Thread.sleep(3000); // 不释放锁
} catch (InterruptedException e) {}
System.out.println("线程A结束");
}
}).start();
new Thread(() -> {
synchronized (lock) {
System.out.println("线程B拿到锁");
}
}).start();
}
}
运行结果(重点理解)
bash
线程A拿到锁
(3 秒)
线程A结束
线程B拿到锁
原因解析(关键)
-
sleep()不会释放 synchronized 的锁 -
线程A睡觉了,但仍然霸占着锁
-
线程B只能干等
👉 这就是 sleep = 线程自己睡觉,不管别人
四、代码对比 ②:wait 会释放锁
示例:wait + notify 正确的线程通信
java
public class WaitDemo {
private static final Object lock = new Object();
public static void main(String[] args) {
new Thread(() -> {
synchronized (lock) {
System.out.println("线程A拿到锁");
try {
lock.wait(); // 释放锁,进入等待
} catch (InterruptedException e) {}
System.out.println("线程A被唤醒");
}
}).start();
new Thread(() -> {
synchronized (lock) {
System.out.println("线程B拿到锁");
lock.notify(); // 唤醒等待的线程
}
}).start();
}
}
运行结果
java
线程A拿到锁
线程B拿到锁
线程A被唤醒
原因解析(重点)
-
wait()会:-
释放锁
-
当前线程进入等待队列
-
-
notify():-
只是通知
-
线程A必须 重新抢到锁 才能继续执行
-
👉 这就是 wait = 放下锁,等别人叫你
五、为什么 wait 必须在 synchronized 中?
错误示例(面试常问):
java
lock.wait(); // ❌ 直接报异常
报什么错?
java
IllegalMonitorStateException
原因(必须会说)
因为
wait/notify是 对象级别的线程通信机制只有持有该对象的锁,才能调用它们。
六、底层记忆法(非常好记)
用生活比喻
| Java | 现实 |
|---|---|
| synchronized | 占用会议室 |
| sleep | 在会议室里睡觉(不让别人进) |
| wait | 离开会议室等通知 |
| notify | 叫人回来开会 |
七、面试标准回答模板(直接背)
sleep 是 Thread 类的方法,用于让线程休眠一段时间,但不会释放锁;
wait 是 Object 类的方法,用于线程间通信,会释放锁,必须在 synchronized 中使用,通常配合 notify 或 notifyAll 使用。
八、你是否真的学会了?自测 3 问
1️⃣ sleep 会不会释放锁?
2️⃣ wait 能不能单独调用?
3️⃣ notify 之后线程一定马上执行吗?