baeldung 2024-01-08
1. 概述
在本文中,我们将简要介绍 Java 核心库中的标准 sleep() 和 wait() 方法,并理解它们之间的异同。
2. wait 与 sleep 的主要区别
简单来说,wait() 是一个用于线程同步的实例方法。
它可以在任意对象上调用(因为它定义在 java.lang.Object 类中),但只能在同步代码块(synchronized block)中调用。调用 wait() 会释放该对象上的锁,以便其他线程可以获取该锁并继续执行。
另一方面,Thread.sleep() 是一个静态方法,可以在任何上下文中调用。Thread.sleep() 暂停当前线程的执行,但不会释放任何已持有的锁。
下面是一个非常简单的示例,展示了这两个核心 API 的基本用法:
private static Object LOCK = new Object();
private static void sleepWaitExamples() throws InterruptedException {
Thread.sleep(1000);
System.out.println(
"线程 '" + Thread.currentThread().getName() +
"' 在休眠 1 秒后被唤醒");
synchronized (LOCK) {
LOCK.wait(1000);
System.out.println("对象 '" + LOCK + "' 在等待 1 秒后被唤醒");
}
}
运行上述示例将产生如下输出:
线程 ‘main’ 在休眠 1 秒后被唤醒
对象 ‘java.lang.Object@31befd9f’ 在等待 1 秒后被唤醒
3. 唤醒 wait 与 sleep
当我们使用 sleep() 方法时,线程会在指定的时间间隔后自动恢复运行,除非在此期间被中断(interrupted)。
而 wait() 的唤醒机制则稍微复杂一些。我们可以通过在所等待的监视器(monitor)上调用 notify() 或 notifyAll() 方法来唤醒处于等待状态的线程。
- 如果希望唤醒所有处于等待状态的线程,请使用
notifyAll()。 - 与
wait()方法本身一样,notify()和notifyAll()也必须在同步上下文中调用。
例如,以下是如何使用 wait() 等待另一个线程完成操作:
synchronized (b) {
while (b.sum == 0) {
System.out.println("等待 ThreadB 完成...");
b.wait();
}
System.out.println("ThreadB 已完成。该线程计算的总和为: " + b.sum);
}
然后,另一个线程可以通过在其监视器上调用 notify() 来唤醒等待的线程:
int sum;
@Override
public void run() {
synchronized (this) {
int i = 0;
while (i < 100000) {
sum += i;
i++;
}
notify();
}
}
运行此示例将产生如下输出:
等待 ThreadB 完成…
ThreadB 已完成。该线程计算的总和为: 704982704
4. 结论
本文简要介绍了 Java 中 wait 与 sleep 的语义和使用场景。
- 通常情况下,应使用
sleep()来控制单个线程的执行时间; - 而
wait()则用于多线程之间的协作与同步。
当然,关于线程同步还有更多内容值得深入探索——但在深入之前,扎实掌握这些基础知识至关重要。