在 Java 中,线程间的通信可以通过 wait()
、notify()
和 notifyAll()
这三个方法实现。这些方法是 Java 线程 Thread
类的一部分,它们与 synchronized
关键字一起使用,以实现线程间的协调。
基本概念
- wait():当一个线程执行到
wait()
方法时,它会释放它持有的所有锁,并进入等待状态。直到其他线程调用相同对象的notify()
或notifyAll()
方法,它才会被唤醒。 - notify():唤醒在此对象监视器上等待的单个线程。选择哪个线程被唤醒是不确定的。
- notifyAll():唤醒在此对象监视器上等待的所有线程。
工作机制
- 加锁:在调用
wait()
、notify()
或notifyAll()
之前,必须先通过synchronized
关键字获取对象的锁。 - 等待:当线程调用
wait()
时,它会释放锁并进入等待状态,直到被其他线程唤醒。 - 唤醒:当其他线程调用
notify()
或notifyAll()
时,它会唤醒一个或所有等待的线程。 - 重新竞争锁:被唤醒的线程需要重新竞争获取对象的锁,才能继续执行。
使用场景
- 当一个线程需要等待某个条件成立时,可以使用
wait()
方法。 - 当条件成立时,其他线程可以通过
notify()
或notifyAll()
唤醒等待的线程。
示例
假设有两个线程,一个生产者和一个消费者:
public class SharedObject {private boolean available = false;public synchronized void waitForSignal() throws InterruptedException {while (!available) {wait(); // 等待信号}}public synchronized void sendSignal() {available = true;notify(); // 发送信号}
}
在这个例子中,waitForSignal()
方法中的 wait()
会阻塞,直到 sendSignal()
方法中的 notify()
被调用。
注意事项
- 必须在
synchronized
块或方法中调用wait()
、notify()
和notifyAll()
。 - 调用
wait()
时,线程会释放锁,调用结束后,线程会重新尝试获取锁。 - 使用
notify()
时,只有一个等待的线程会被唤醒,而notifyAll()
会唤醒所有等待的线程。 - 为了避免死锁,通常推荐使用
java.util.concurrent
包中的Lock
接口和相关实现,因为它们提供了更灵活的锁操作。
通过合理使用 wait()
、notify()
和 notifyAll()
方法,线程可以在需要时等待,条件满足时被唤醒,从而实现线程间的有效通信。