当前位置:首页 > Java > 正文

深入理解Java线程通信机制(wait与notify使用详解)

Java多线程同步编程中,wait()notify() 是两个非常核心的方法,它们定义在 Object 类中,用于实现线程之间的协作与通信。本文将从基础概念出发,通过通俗易懂的例子,帮助你彻底掌握这两个方法的用法。

深入理解Java线程通信机制(wait与notify使用详解) Java wait notify  Java线程通信 Java多线程同步 Object类方法 第1张

一、什么是 wait() 和 notify()?

wait()notify()Java Object类方法,用于在多个线程之间进行协调。它们必须在同步代码块(即 synchronized 块)中调用,否则会抛出 IllegalMonitorStateException 异常。

  • wait():使当前线程进入等待状态,并释放它持有的对象锁。线程会一直等待,直到其他线程调用该对象的 notify()notifyAll() 方法。
  • notify():唤醒在此对象监视器上等待的单个线程(如果有多个线程在等待,则随机唤醒一个)。
  • notifyAll():唤醒在此对象监视器上等待的所有线程。

二、为什么需要 wait/notify?

想象一个生产者-消费者模型:生产者线程生成数据并放入缓冲区,消费者线程从缓冲区取出数据。如果缓冲区满了,生产者应暂停;如果缓冲区空了,消费者应暂停。这时就需要线程间通信——这正是 Java线程通信 的典型应用场景。

三、基本使用示例

下面是一个简单的“任务完成通知”例子:

public class WaitNotifyExample {    private static final Object lock = new Object();    private static boolean taskCompleted = false;    public static void main(String[] args) throws InterruptedException {        // 启动等待线程        Thread waiter = new Thread(() -> {            synchronized (lock) {                while (!taskCompleted) {                    try {                        System.out.println("等待任务完成...");                        lock.wait(); // 释放锁并等待                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                }                System.out.println("任务已完成!继续执行。");            }        });        // 启动通知线程        Thread notifier = new Thread(() -> {            try {                Thread.sleep(2000); // 模拟任务耗时            } catch (InterruptedException e) {                e.printStackTrace();            }            synchronized (lock) {                taskCompleted = true;                System.out.println("任务完成,通知等待线程...");                lock.notify(); // 唤醒一个等待线程            }        });        waiter.start();        notifier.start();        waiter.join();        notifier.join();    }}

四、关键注意事项

  1. 必须在 synchronized 块中调用:因为 wait()notify() 操作的是对象的监视器(monitor),只有持有该对象锁的线程才能调用这些方法。
  2. 使用 while 而不是 if 检查条件:这是为了防止“虚假唤醒”(spurious wakeup)。即使没有被显式唤醒,线程也可能被操作系统意外唤醒,因此必须在循环中重新检查条件。
  3. notify() vs notifyAll():如果你不确定有多少线程在等待,或者多个线程可能因不同条件而等待,建议使用 notifyAll() 以避免死锁。
  4. 调用 wait() 后,线程会释放锁;当被唤醒后,它会重新尝试获取锁,然后继续执行。

五、常见误区

很多初学者容易混淆 wait()Thread.sleep()

  • sleep() 不释放锁,只是让线程暂停执行一段时间。
  • wait() 会释放锁,并且必须配合 notify() 使用才能恢复。

六、总结

掌握 Java wait notify 机制是编写高效、安全的多线程程序的关键。通过合理使用 wait()notify()notifyAll(),你可以实现复杂的线程协作逻辑,如生产者-消费者、线程池任务调度等。

记住:始终在 synchronized 块中使用它们,用 while 循环检查条件,并根据场景选择 notify()notifyAll()。这样,你就能写出健壮的 Java多线程同步 代码!