Sleep 和 Wait 的区别、比较与简单使用
sleep()
和 wait()
都是与线程(或进程)等待(休眠)一段时间相关的操作,且 sleep() 和 wait() 方法都可以响应 interrupt 中断,也就是线程在休眠的过程中,如果收到中断信号,都可以进行响应,并抛出 InterruptedException 异常。让我们来看看它们的不同之处。
区别一:语法使用不同
Thead.Sleep() 代码示例如下:
1 | private static void sleep() { |
Object.Wait() 方法必须配合 synchronized 一起使用,不然在运行时就会抛出 IllegalMonitorStateException 的异常,示例代码如下:
1 | private static void Wait() { |
这段代码展示了一个简单的Java程序,其中包含了使用wait()和notify()的线程等待和唤醒的示例。让我逐步解释这段代码的流程:
1.Wait方法开始执行,Wait开始输出。
2.第一个线程进入synchronized (lock)块,调用lock.wait(2000)并等待2秒。
3.第二个线程进入synchronized (lock)块,调用lock.wait(1000)并等待1秒。
4.第二个线程调用lock.notify()来唤醒等待的线程。
5.第一个线程被唤醒,计算等待时间,输出”Wait结束”和等待时间。
6.第二个线程输出”线程被唤醒”。
需要注意的是,wait() 和 notify() 方法必须在 synchronized 块中调用,并且需要使用相同的锁(示例里使用的是 lock 对象)。
执行结果:
1 | Wait开始 |
区别二:所属类不同
Sleep() 属于 Thread 类的方法,而 Wait() 属于 Object 类的方法。
区别三:唤醒方式不同
sleep() 方法需要传递一个休眠时间的参数,用于让当前线程休眠一段时间。在超过休眠时间之后,线程将会自动被唤醒,不需要其他线程进行通知。当我们的线程睡眠时间太长,我们需要提前唤醒睡眠的线程时,我们可以使用 Thread.interrupt() 方法。此方法表示中断这个线程。在我们的实际运用当中,interrupt() 方法可以实现终止线程的睡眠,提前唤醒线程。
wait() 方法可以传递休眠时间参数,也可以不传递任何参数。不传递任何参数时表示永久休眠,直到另一个线程调用了 notify 或 notifyAll 之后,休眠的线程才能被唤醒。也就是说 sleep 方法具有主动唤醒功能,而不传递任何参数的 wait 方法只能被动的被唤醒。Thread.interrupt() 方法对 wait() 方法依然存在终止线程的睡眠,提前唤醒线程的效果。
区别四:释放锁资源不同
首先给定结论:wait 方法会主动的释放锁,而 sleep 方法则不会。
wait() 方法代码示例:
1 | private static void lockOfWait() throws Exception { |
该代码使用了 wait() 用于线程休眠2秒,在另一个主线程种尝试获取锁。如果成功获取到锁,则说明 wait() 在休眠时会释放锁,反之则说明不会释放锁。执行结果如下:
1 | 新线程获取到锁:2023-08-11F20:03:49.027 |
从上述结果可以看出,当调用了 wait() 之后,主线程立马尝试获取锁成功了,这就说明 wait() 休眠时是释放锁的。
sleep() 方法代码示例:
1 | private static void lockOfSleep() throws Exception { |
该代码使用了 sleep() 用于线程休眠2秒,在另一个主线程种尝试获取锁。如果成功获取到锁,则说明 sleep() 在休眠时会释放锁,反之则说明不会释放锁。执行结果如下:
1 | 新线程获取到锁:2023-08-11F20:08:20.139 |
从上述结果可以看出,在调用了 sleep() 之后,在主线程里尝试获取锁却没有成功,只有 sleep() 执行完之后释放了锁,主线程才正常的得到了锁,这说明 sleep() 在休眠时并不会释放锁。
区别五:线程进入状态不同
调用 sleep() 方法及有参 wait() 方法线程会进入 TIMED_WAITING 有时限等待状态,而调用无参数的 wait() 方法,线程会进入 WAITING 无时限等待状态。
1 | private static void getStatus() throws Exception { |
代码执行结果如下:
1 | wait() 方法后状态为:WAITING |
Sleep() 和 Wait() 比较
安全性:
wait() 安全性较高:wait() 必须在同步块中调用,它会释放锁,等待其他线程通知,因此避免了死锁的风险。它在等待时会放弃对象的锁,允许其他线程进入同步块,然后在被唤醒时重新尝试获取锁。
sleep()安全性较低:sleep()不会释放锁,它只是让线程休眠一段时间。如果在同步块内调用sleep(),其他线程无法进入同步块,可能导致死锁。
常用业务:
wait() 用于线程间通信:wait() 适合用于多个线程之间的通信,其中一个线程等待另一个线程的通知。常用于生产者-消费者模式、多线程协作等场景。
sleep() 用于暂停执行:sleep() 用于暂停当前线程的执行,常用于模拟等待、定时任务等场景。
稳定性:
wait() 稳定性较高:在正确使用的情况下,wait() 能够稳定地实现线程之间的通信,避免了资源竞争和死锁的问题。但需要注意正确处理 InterruptedException。
资源占用:
wait() 会释放对象的锁,允许其他线程进入同步块,从而避免了资源的长时间占用。
sleep() 不会释放锁,因此可能会造成资源的长时间占用,需要谨慎使用。
通知机制:
wait() 需要配合 notify() 或 notifyAll() 来通知等待线程继续执行。这个通知机制允许多个线程等待同一个对象上的通知,非常适合用于线程间的协调和通信。
sleep() 没有内建的通知机制,只是简单的休眠一段时间。不适合多线程协作,通常用于暂停执行或定时任务。
总结
wait() 和 sleep() 是Java多线程编程中的重要方法,虽然它们都能让线程暂停,但用途不同。wait() 常用于线程间通信,释放锁、等待通知,避免死锁,适合协作场景;sleep() 多用于暂停执行,不释放锁,适合模拟等待或定时任务。选择方法时需考虑安全性、业务需求和稳定性。了解这两者差异,能更高效地设计多线程程序,提升应用的性能和可维护性。
最后附上本文所写源代码:Sleep和Wait的的区别、比较与简单使用
- 标题: Sleep 和 Wait 的区别、比较与简单使用
- 作者: HYF
- 创建于 : 2023-08-11 21:26:32
- 更新于 : 2024-07-27 21:21:52
- 链接: https://youfeng.ink/sleep&&wait-516dcd7bafcc/
- 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。