JAVA:深入理解 wait() 和 sleep() 的区别与实战
1、简述
在进行 Java 并发编程时,wait()
和 sleep()
是两个非常常见的方法。很多初学者常常将它们混淆,本文将从底层原理、使用语义、对象归属、场景应用等方面深入剖析二者的区别,并通过实际代码加深理解。
2、基本定义
Thread.sleep(long millis)
- 属于
Thread
类的静态方法 - 用于让当前线程进入休眠状态指定时间
- 不释放任何对象的锁
Object.wait(long millis)
- 属于
Object
类的实例方法 - 当前线程在获取某个对象锁后可以调用它
- 调用后线程进入等待状态,并释放对象锁
关键区别对比
特性 | sleep() | wait() |
---|---|---|
所属类 | Thread | Object |
是否释放锁 | ❌ 不释放锁 | ✅ 释放锁 |
是否需要同步块 | ❌ 不需要 | ✅ 必须在同步代码块中(synchronized )调用 |
用途 | 暂停当前线程 | 线程间通信与协作 |
唤醒方式 | 时间到自动唤醒 | notify() 或 notifyAll() 手动唤醒 |
抛出异常 | InterruptedException | InterruptedException |
3、实战代码示例
示例 1:sleep 不释放锁的表现
public class SleepLockDemo {public static void main(String[] args) {final Object lock = new Object();Thread t1 = new Thread(() -> {synchronized (lock) {System.out.println("T1 acquired lock, sleeping 5s...");try {Thread.sleep(5000); // 不释放锁} catch (InterruptedException e) {e.printStackTrace();}System.out.println("T1 done.");}});Thread t2 = new Thread(() -> {synchronized (lock) {System.out.println("T2 acquired lock.");}});t1.start();try { Thread.sleep(100); } catch (Exception e) {}t2.start();}
}
输出:
T1 acquired lock, sleeping 5s...
(T2 阻塞中,等待锁)
T1 done.
T2 acquired lock.
分析:
- T1 使用
sleep
睡眠时 不会释放锁 - T2 一直阻塞在
synchronized (lock)
上
示例 2:wait 会释放锁
public class WaitNotifyDemo {public static void main(String[] args) {final Object lock = new Object();Thread t1 = new Thread(() -> {synchronized (lock) {System.out.println("T1 acquired lock, calling wait()...");try {lock.wait(); // 会释放锁System.out.println("T1 resumed.");} catch (InterruptedException e) {e.printStackTrace();}}});Thread t2 = new Thread(() -> {try { Thread.sleep(1000); } catch (Exception e) {}synchronized (lock) {System.out.println("T2 acquired lock, notifying...");lock.notify(); // 唤醒 T1}});t1.start();t2.start();}
}
输出:
T1 acquired lock, calling wait()...
T2 acquired lock, notifying...
T1 resumed.
分析:
wait()
会释放锁,T2 得以获取锁并调用notify()
notify()
唤醒等待中的 T1
4、常见面试问题总结
问题 | 解答 |
---|---|
wait() 和 sleep() 有什么根本区别? | wait() 用于线程通信,释放锁;sleep() 用于线程暂停,不释放锁 |
wait() 能不能放在同步块外面用? | ❌ 不能,必须持有对象锁,否则抛出 IllegalMonitorStateException |
sleep() 会不会影响锁? | ❌ 不会,线程持有的锁不会释放 |
wait() 会自动恢复吗? | ❌ 不会,必须被其他线程 notify() 或 notifyAll() |
5、总结
项目 | sleep() | wait() |
---|---|---|
类 | Thread | Object |
用途 | 暂停当前线程 | 线程间协调与通信 |
是否释放锁 | 否 | 是 |
是否依赖同步 | 否 | 是(必须加锁) |
唤醒方式 | 自动时间唤醒 | 手动唤醒(notify) |
使用建议
✅ 使用 sleep()
场景:
- 模拟延迟(定时任务、重试)
- 轮询等待(不推荐,性能差)
✅ 使用 wait()
场景:
- 多线程协作模型(生产者-消费者)
- 阻塞线程等待某条件达成