Java Thread.sleep与Object.wait的锁释放行为差异
Java 多线程编程中,控制线程暂停的两种最常见方式是 Thread.sleep 和 Object.wait。虽然它们都能让线程停止运行,但在锁的释放行为上有着本质的区别。理解这一差异对于避免死锁和提高并发性能至关重要。
1. 验证 Thread.sleep 的锁持有行为
Thread.sleep 会让当前线程休眠指定时间,但不会释放它持有的任何锁。
创建一个名为 SleepDemo 的 Java 类,并输入以下代码:
public class SleepDemo {
private static final Object lock = new Object();
public static void main(String[] args) {
Thread threadA = new Thread(() -> {
synchronized (lock) {
System.out.println("线程A:获取锁,开始睡觉");
try {
// 休眠 5 秒
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程A:睡醒了,释放锁");
}
});
Thread threadB = new Thread(() -> {
synchronized (lock) {
System.out.println("线程B:获取到锁了");
}
});
threadA.start();
// 确保 A 先启动
try { Thread.sleep(100); } catch (InterruptedException e) {}
threadB.start();
}
}
运行程序,观察控制台输出。你会发现“线程B:获取到锁了”这句话会在 5 秒后才打印出来。这证明线程 A 在睡眠期间依然占有着 lock 对象,线程 B 只能阻塞等待。
2. 验证 Object.wait 的锁释放行为
Object.wait 必须在 synchronized 块或方法中调用。与 sleep 不同,wait 方法会释放当前线程持有的对象锁,允许其他线程进入同步块。
创建一个名为 WaitDemo 的 Java 类,并输入以下代码:
public class WaitDemo {
private static final Object lock = new Object();
public static void main(String[] args) {
Thread threadA = new Thread(() -> {
synchronized (lock) {
System.out.println("线程A:获取锁,开始等待");
try {
// 等待 5 秒或被唤醒,此处会释放锁
lock.wait(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程A:等待结束,重新拿到锁并执行");
}
});
Thread threadB = new Thread(() -> {
synchronized (lock) {
System.out.println("线程B:获取到锁了");
}
});
threadA.start();
try { Thread.sleep(100); } catch (InterruptedException e) {}
threadB.start();
}
}
运行程序。你会发现“线程B:获取到锁了”这句话几乎是立即打印的。这证明线程 A 调用 wait 后立刻释放了锁,线程 B 随即进入了同步块。
3. 核心差异对比表
以下表格总结了两者在锁处理上的关键区别:
| 特性 | Thread.sleep | Object.wait |
|---|---|---|
| 锁行为 | 不释放锁 | 释放锁 |
| 所属类 | java.lang.Thread |
java.lang.Object |
| 使用位置 | 任何地方 | 必须在 synchronized 代码块或方法内 |
| 唤醒方式 | 时间结束、interrupt |
notify/notifyAll、时间结束、interrupt |
| 恢复执行 | 时间到了自动恢复 | 需重新竞争获取锁 |
4. 执行流程可视化
为了更直观地理解两者在锁状态上的流转,请参考以下流程图:
graph TD
subgraph "Thread.sleep 流程"
A1["线程进入 synchronized 块"] --> B1["调用 Thread.sleep()"]
B1 --> C1["线程休眠 (保持运行状态)"]
C1 --> D1["持有对象锁"]
D1 --> E1["其他线程尝试获取锁 -> 阻塞"]
E1 --> F1["休眠时间结束"]
F1 --> G1["继续执行代码"]
end
subgraph "Object.wait 流程"
A2["线程进入 synchronized 块"] --> B2["调用 lock.wait()"]
B2 --> C2["线程进入等待集"]
C2 --> D2["释放对象锁"]
D2 --> E2["其他线程可获取锁并执行"]
E2 --> F2["收到 notify 或超时"]
F2 --> G2["重新竞争锁"]
G2 --> H2["拿到锁后继续执行"]
end

暂无评论,快来抢沙发吧!