在 Java 中,sleep()
和wait()
都用于线程控制,但它们的使用场景、工作机制和功能有本质区别,主要体现在以下几个方面:
1. 所属类不同
sleep()
是java.lang.Thread
类的静态方法,通过Thread.sleep()
调用。wait()
是java.lang.Object
类的实例方法,必须通过对象实例调用(如obj.wait()
)。
2. 对锁的影响不同
这是两者最核心的区别:
sleep()
不会释放锁:
当线程执行sleep()
时,会暂停执行指定时间,但持有当前对象的锁不会释放。其他线程无法获取该锁,只能等待sleep()
结束后线程继续执行。wait()
会释放锁:
当线程执行wait()
时,会释放当前对象的锁,并进入该对象的等待队列(waiting pool)。其他线程可以获取该锁并执行同步代码块,直到被notify()
/notifyAll()
唤醒。
3. 使用场景不同
sleep()
用于暂停执行:
通常用于控制线程执行的时间间隔,让线程 “休眠” 一段时间后自动恢复,不依赖其他线程的通知。
示例:try { // 线程休眠1秒,不释放锁 Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); }
wait()
用于线程间通信:
通常用于线程间的协作,让线程等待某个条件满足(如资源就绪),需其他线程调用notify()
/notifyAll()
唤醒。
示例:synchronized (obj) { try { // 释放obj的锁,进入等待队列 obj.wait(); } catch (InterruptedException e) { e.printStackTrace(); } }
4. 唤醒方式不同
sleep()
自动唤醒:
只需等待指定时间结束,线程会自动从阻塞状态恢复到就绪状态。wait()
需主动唤醒:
必须由其他线程调用同一对象的notify()
(唤醒一个等待线程)或notifyAll()
(唤醒所有等待线程)才能恢复。若未被唤醒,线程会一直处于等待状态。
此外,wait(long timeout)
也支持超时自动唤醒(类似sleep()
的时间参数)。
5. 调用前提不同
sleep()
可在任何地方调用:
无需在同步代码块(synchronized
)中使用,即使在非同步环境下也能正常工作。wait()
必须在同步环境中调用:
必须在synchronized
代码块或方法中调用,否则会抛出IllegalMonitorStateException
。因为wait()
需要释放对象锁,而只有持有锁的线程才能释放锁。
6. 异常处理
两者都会抛出InterruptedException
(受检异常),必须捕获或声明抛出。该异常在线程休眠 / 等待时被中断(如其他线程调用interrupt()
)时触发。
总结对比表
特性 | sleep() |
wait() |
---|---|---|
所属类 | Thread (静态方法) |
Object (实例方法) |
锁释放 | 不释放锁 | 释放锁 |
使用场景 | 控制执行间隔 | 线程间通信(等待 / 唤醒) |
唤醒方式 | 时间到自动唤醒 | 需notify() /notifyAll() 或超时 |
调用前提 | 无需同步环境 | 必须在synchronized 中调用 |
典型使用示例
sleep()
示例(不释放锁)
public class SleepDemo {
public static void main(String[] args) {
Object lock = new Object();
new Thread(() -> {
synchronized (lock) {
System.out.println("线程1获取锁,开始执行");
try {
// 休眠2秒,不释放lock锁
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程1执行完毕");
}
}).start();
new Thread(() -> {
synchronized (lock) {
// 需等待线程1释放锁后才能执行
System.out.println("线程2获取锁,开始执行");
}
}).start();
}
}
输出:
线程1获取锁,开始执行
(等待2秒)
线程1执行完毕
线程2获取锁,开始执行
wait()
示例(释放锁)
public class WaitDemo {
public static void main(String[] args) {
Object lock = new Object();
// 等待线程
new Thread(() -> {
synchronized (lock) {
System.out.println("等待线程:获取锁,开始等待");
try {
// 释放lock锁,进入等待队列
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("等待线程:被唤醒,继续执行");
}
}).start();
// 唤醒线程
new Thread(() -> {
try {
Thread.sleep(1000); // 确保等待线程先执行
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (lock) {
System.out.println("唤醒线程:获取锁,准备唤醒");
lock.notify(); // 唤醒等待线程
System.out.println("唤醒线程:执行完毕");
}
}).start();
}
}
输出:
等待线程:获取锁,开始等待
(等待1秒)
唤醒线程:获取锁,准备唤醒
唤醒线程:执行完毕
等待线程:被唤醒,继续执行
总之,sleep()
是线程自身的休眠,不涉及锁的释放;wait()
是线程间的协作机制,必须配合锁和唤醒操作使用,核心是释放锁并等待通知。