Java线程的sleep和wait的区别
在Java中,Thread.sleep()
和 Object.wait()
都可以让线程暂停执行,但是它们的作用机制和使用场景是不同的。下面是这两个方法的主要区别:
Thread.sleep(long millis, int nanos)
- 参数:
millis
是毫秒数,nanos
是额外的纳秒数(0到999,999之间)。 - 行为:当前线程将暂停执行至少指定的毫秒数加上纳秒数。实际暂停时间可能会更长,因为系统调度或其他因素可能会导致额外的延迟。
- 锁的影响:
Thread.sleep()
不会影响线程所持有的锁。如果线程在调用Thread.sleep()
之前持有了某个对象的锁,那么即使在线程暂停期间,这个锁也不会被释放。 - 异常处理:如果另一个线程中断了正在睡眠的线程,那么会抛出
InterruptedException
,并且清除中断状态。因此,在调用Thread.sleep()
后应该总是捕获InterruptedException
并进行适当的处理。 - 应用场景:适用于简单的定时任务,比如每隔一段时间执行一次某些操作。
-
用法
基本用法:使用 Thread.sleep(millis)
或 Thread.sleep(millis, nanos)
让线程暂停指定的时间。
异常处理:必须捕获 InterruptedException
,因为如果在 sleep
期间线程被中断,就会抛出这个异常。处理中断异常的一种常见做法是重新设置中断标志,然后退出当前操作。
示例
try {
Thread.sleep(1000); // 使当前线程暂停1秒钟
} catch (InterruptedException e) {
// 重设中断状态
Thread.currentThread().interrupt();
System.out.println("Thread was interrupted during sleep.");
}
Object.wait()
- 参数:
wait()
可以接受三个不同的签名:void wait()
: 无限期等待,直到被其他线程唤醒。void wait(long timeout)
: 等待指定毫秒数后自动醒来。void wait(long timeout, int nanos)
: 等待指定的毫秒数加纳秒数后自动醒来。
- 行为:当前线程必须首先获取调用
wait()
方法的对象的锁。调用wait()
后,线程会释放该对象的锁,并进入等待队列。直到其他线程调用了同一个对象的notify()
或notifyAll()
方法,或者指定了超时时间并已过期,线程才会重新获取锁并继续执行。 - 锁的影响:与
Thread.sleep()
不同,Object.wait()
会导致线程释放它所持有的对象锁,这样其他线程就有机会获得该锁并执行。 - 异常处理:同样地,如果线程在等待期间被中断,
wait()
方法会抛出InterruptedException
。 - 应用场景:适用于需要线程间协作的场合,比如当一个线程需要等待某个条件成立(如缓冲区中有数据可用)才能继续执行时。
-
用法
同步上下文:Object.wait()
必须在 synchronized
块内调用,因为它需要当前线程拥有该对象的锁。
唤醒机制:Object.notify()
只会随机唤醒一个等待中的线程,而 Object.notifyAll()
会唤醒所有等待中的线程。
异常处理:同样需要捕获 InterruptedException
。
示例
synchronized (sharedResource) {
while (!condition) { // condition 是一个布尔值,表示等待的条件
try {
sharedResource.wait(); // 线程等待,直到被唤醒
} catch (InterruptedException e) {
// 重设中断状态
Thread.currentThread().interrupt();
System.out.println("Thread was interrupted during wait.");
return;
}
}
// 执行条件满足后的操作
}
深入理解
- 锁的管理:
Thread.sleep()
保持锁,而Object.wait()
释放锁。这对于线程间协作非常重要,因为Object.wait()
允许其他线程访问共享资源,而Thread.sleep()
不允许。 - 线程间通信:
Object.wait()
和Object.notify()
/Object.notifyAll()
提供了一种方式让线程间进行通信。一个线程可以等待特定条件,而另一个线程可以在条件满足时通知等待的线程。 - 死锁预防:由于
Object.wait()
释放锁,所以它可以用来避免死锁。相反,Thread.sleep()
保持锁,如果使用不当,这可能会导致死锁。
注意事项
Thread.sleep()
和Object.wait()
都是静态方法,但Object.wait()
必须在synchronized
上下文中调用。- 使用
Object.wait()
和Object.notify()
/Object.notifyAll()
时,一定要确保这些方法是在同一个对象上被调用的,否则线程可能永远不会被唤醒。 - 在处理
InterruptedException
时,通常的做法是恢复中断状态(如果需要的话),以便调用栈中的其他方法能够正确地响应中断。
你可以根据你的具体需求选择合适的方法来控制线程的行为。如果你只是想简单地暂停线程而不涉及线程间的交互,那么 Thread.sleep()
就足够了;如果你需要实现更复杂的线程间同步逻辑,那么应该考虑使用 Object.wait()
以及相应的 notify()
或 notifyAll()
方法。