Java高频面试之并发编程-08
hello啊,各位观众姥爷们!!!本baby今天来报道了!哈哈哈哈哈嗝🐶
面试官:说说sleep和wait的区别?
1. 核心区别总结
特性 | sleep() | wait() |
---|---|---|
所属类 | Thread 类的静态方法 | Object 类的实例方法 |
锁的释放 | 不释放锁(保持当前线程持有的锁) | 释放锁(让其他线程获取锁) |
调用条件 | 可在任何地方调用 | 必须在 synchronized 同步块或方法中调用 |
唤醒机制 | 时间到自动唤醒 | 需其他线程调用 notify() /notifyAll() |
作用范围 | 控制线程休眠 | 用于线程间通信(协调共享资源访问) |
异常处理 | 需捕获 InterruptedException | 需捕获 InterruptedException |
2. 详细对比
(1) 锁的行为
-
sleep()
线程调用sleep()
后进入休眠状态,但不会释放已持有的锁。其他线程无法获取该锁,可能导致阻塞。synchronized (lock) {Thread.sleep(1000); // 持有锁休眠,其他线程无法进入同步块 }
-
wait()
调用wait()
会立即释放当前对象的锁,允许其他线程获取锁并执行同步代码块。synchronized (lock) {lock.wait(); // 释放锁,其他线程可进入同步块 }
(2) 使用场景
-
sleep()
用于让线程暂停执行一段时间(如定时任务、模拟延迟)。// 定时任务:每秒执行一次 while (true) {doTask();Thread.sleep(1000); // 休眠 1 秒 }
-
wait()
用于线程间协作,等待某个条件满足(如生产者-消费者模型)。// 消费者等待队列非空 synchronized (queue) {while (queue.isEmpty()) {queue.wait(); // 释放锁,等待生产者通知}queue.poll(); }
(3) 唤醒机制
-
sleep()
休眠时间结束后自动恢复,或通过interrupt()
中断休眠(抛出InterruptedException
)。 -
wait()
必须由其他线程调用同一对象的notify()
或notifyAll()
唤醒,或等待超时(若指定了时间)。
3. 代码示例
sleep()
示例
public class SleepDemo {public static void main(String[] args) {new Thread(() -> {synchronized (SleepDemo.class) {System.out.println("线程 A 获取锁,开始休眠 3 秒");try {Thread.sleep(3000); // 休眠但不释放锁} catch (InterruptedException e) {e.printStackTrace();}System.out.println("线程 A 唤醒");}}).start();new Thread(() -> {synchronized (SleepDemo.class) {System.out.println("线程 B 获取锁");}}).start();}
}
输出:
线程 A 获取锁,开始休眠 3 秒
(等待 3 秒后)
线程 A 唤醒
线程 B 获取锁
现象:线程 B 必须等待线程 A 释放锁后才能执行。
wait()
示例
public class WaitDemo {public static void main(String[] args) {Object lock = new Object();new Thread(() -> {synchronized (lock) {System.out.println("线程 A 获取锁,并等待");try {lock.wait(); // 释放锁} catch (InterruptedException e) {e.printStackTrace();}System.out.println("线程 A 被唤醒");}}).start();new Thread(() -> {synchronized (lock) {System.out.println("线程 B 获取锁,唤醒线程 A");lock.notify();}}).start();}
}
输出:
线程 A 获取锁,并等待
线程 B 获取锁,唤醒线程 A
线程 A 被唤醒
现象:线程 A 调用
wait()
后释放锁,线程 B 可以获取锁并唤醒线程 A。
4. 常见问题与注意事项
-
为什么
wait()
必须在同步块中调用?wait()
和notify()
依赖于对象的监视器锁(Monitor),调用前必须获取锁,否则抛出IllegalMonitorStateException
。- 这是为了避免竞态条件(Race Condition),确保线程在安全状态下等待或唤醒。
-
sleep()
是否会释放锁?- 不会。
sleep()
是线程自身的行为,与锁无关。
- 不会。
-
如何选择
sleep()
和wait()
?- 需要暂停线程但不涉及锁协调 →
sleep()
。 - 需要线程间协作并释放锁 →
wait()
+notify()
。
- 需要暂停线程但不涉及锁协调 →
-
避免死锁:
- 若线程调用
wait()
后未被唤醒,将永久阻塞。确保逻辑中始终有唤醒机制。
- 若线程调用
总结
sleep()
:单纯让线程休眠,不涉及锁协调,适用于定时任务或延迟操作。wait()
:用于线程间通信,需与notify()
配合,确保共享资源的安全访问。- 核心区别:
sleep()
不释放锁,wait()
释放锁。