Java wait() 方法详解:线程同步与协调的利器193


在Java并发编程中,`wait()` 方法是 `Object` 类中的一个重要方法,用于实现线程间的通信和同步。它允许一个线程暂停执行,等待另一个线程发出信号或超时,从而实现协调工作和避免竞争条件。理解 `wait()` 方法的机制和使用方法对于编写高效、可靠的多线程程序至关重要。

与 `notify()` 和 `notifyAll()` 方法一起,`wait()` 方法构成了 Java 中线程间通信的基本机制。它们都依赖于对象的内置锁(monitor),保证线程操作的原子性和互斥性。让我们深入探讨 `wait()` 方法的细节。

`wait()` 方法的工作机制

`wait()` 方法的核心作用是将当前线程置于对象的等待队列中,并释放该对象的锁。只有当另一个线程调用该对象的 `notify()` 或 `notifyAll()` 方法时,等待队列中的线程才能被唤醒,重新竞争对象的锁并继续执行。如果没有线程调用 `notify()` 或 `notifyAll()`,则等待线程将一直阻塞在等待队列中,直到超时或被中断。

以下几点是理解 `wait()` 方法的关键:
必须在同步块或同步方法中调用: `wait()` 方法必须在持有目标对象的锁的情况下调用。这意味着它必须在 `synchronized` 块或 `synchronized` 方法内部调用。否则,将抛出 `IllegalMonitorStateException` 异常。
释放锁: 当 `wait()` 方法被调用时,当前线程会自动释放它持有的目标对象的锁。这使得其他线程可以获取该锁并访问共享资源。
进入等待队列: 释放锁后,当前线程进入该对象的等待队列,等待被唤醒。
被唤醒: 当另一个线程调用该对象的 `notify()` 或 `notifyAll()` 方法时,等待队列中的一个或所有线程会被唤醒。唤醒的线程会重新竞争该对象的锁。如果竞争成功,则继续执行;否则,再次进入等待状态。
超时和中断: `wait()` 方法有三个重载版本,分别允许指定超时时间(以毫秒为单位)和是否响应中断。如果超时时间到达,或者线程被中断,则 `wait()` 方法会返回,即使没有被 `notify()` 或 `notifyAll()` 唤醒。

`wait()` 方法的三个重载版本

Java 提供了 `wait()` 方法的三个重载版本:
wait(): 无限期等待,直到被 `notify()` 或 `notifyAll()` 唤醒或被中断。
wait(long timeout): 等待指定毫秒数,或者直到被 `notify()` 或 `notifyAll()` 唤醒或被中断。
wait(long timeout, int nanos): 等待指定毫秒数和纳秒数,或者直到被 `notify()` 或 `notifyAll()` 唤醒或被中断。


`wait()`、`notify()` 和 `notifyAll()` 的配合使用

`wait()` 方法通常与 `notify()` 和 `notifyAll()` 方法一起使用,构成完整的线程间通信机制。`notify()` 方法唤醒等待队列中的一个线程,而 `notifyAll()` 方法唤醒等待队列中的所有线程。选择使用哪个方法取决于具体的应用场景。

例如,在一个生产者-消费者模式中,生产者线程在生产完产品后调用 `notify()` 或 `notifyAll()` 方法唤醒等待产品的消费者线程。而消费者线程在消费完产品后,可以调用 `wait()` 方法等待新的产品。

示例:生产者-消费者模式

以下是一个简单的生产者-消费者模式的示例,展示了 `wait()`、`notify()` 和 `synchronized` 的使用:```java
public class ProducerConsumer {
private int bufferSize = 5;
private int[] buffer = new int[bufferSize];
private int count = 0;
private int in = 0;
private int out = 0;
public synchronized void produce(int value) throws InterruptedException {
while (count == bufferSize) {
wait(); // 缓冲区已满,等待
}
buffer[in] = value;
in = (in + 1) % bufferSize;
count++;
notifyAll(); // 通知消费者
}
public synchronized int consume() throws InterruptedException {
while (count == 0) {
wait(); // 缓冲区为空,等待
}
int value = buffer[out];
out = (out + 1) % bufferSize;
count--;
notifyAll(); // 通知生产者
return value;
}
}
```

异常处理

`wait()` 方法可能会抛出 `InterruptedException` 异常,这通常发生在等待线程被中断时。良好的编程实践要求捕获并处理此异常。

Java 的 `wait()` 方法是实现线程间通信和同步的重要工具。通过理解其工作机制、重载版本以及与 `notify()` 和 `notifyAll()` 方法的配合使用,开发者可以编写出更 robust 和高效的多线程应用程序。 然而,需要注意的是,直接使用 `wait()`、`notify()` 和 `notifyAll()` 方法容易出错,复杂的并发场景建议使用更高层次的并发工具,例如 `BlockingQueue`,来简化代码并避免潜在的错误。

2025-06-08


上一篇:Java方法中断处理:优雅地应对异常和中断

下一篇:深入浅出Tomcat与Java代码的结合:部署、配置与最佳实践