面试题:Java 中的 wait、notify 和 notifyAll 方法有什么作用?

waitnotify 和 notifyAll 是 Java 中用于实现线程间通信和同步的关键方法,它们都是 Object 类的方法,必须在同步代码块或同步方法中使用(即需要持有对象的监视器锁)。它们的作用如下:


1. wait()

  • 作用:使当前线程进入等待状态,并释放持有的对象锁。
  • 行为
    • 调用 wait() 后,当前线程会释放锁,并进入 WAITING 状态。
    • 线程会一直等待,直到其他线程调用 notify() 或 notifyAll() 唤醒它,或者被中断(InterruptedException)。
    • 被唤醒后,线程需要重新获取锁才能继续执行。
  • 使用场景
    • 用于线程间的条件等待,例如生产者-消费者模型。

示例

synchronized (lock) {
    while (conditionNotMet) {
        lock.wait(); // 释放锁并等待
    }
    // 条件满足后继续执行
}

2. notify()

  • 作用:随机唤醒一个正在等待该对象锁的线程。
  • 行为
    • 调用 notify() 后,会从等待队列中随机选择一个线程唤醒。
    • 被唤醒的线程需要重新获取锁才能继续执行。
    • 如果没有线程在等待,则 notify() 不会有任何效果。
  • 使用场景
    • 用于唤醒单个等待线程,例如生产者-消费者模型中的生产者唤醒消费者。

示例

synchronized (lock) {
    // 修改条件
    conditionMet = true;
    lock.notify(); // 唤醒一个等待线程
}

3. notifyAll()

  • 作用:唤醒所有正在等待该对象锁的线程。
  • 行为
    • 调用 notifyAll() 后,会唤醒所有等待队列中的线程。
    • 被唤醒的线程需要竞争获取锁,只有获取锁的线程才能继续执行。
    • 如果没有线程在等待,则 notifyAll() 不会有任何效果。
  • 使用场景
    • 用于唤醒所有等待线程,例如多个消费者等待生产者生产数据。

示例

synchronized (lock) {
    // 修改条件
    conditionMet = true;
    lock.notifyAll(); // 唤醒所有等待线程
}

4. 关键点总结

方法作用释放锁唤醒线程数量使用场景
wait()使当前线程等待并释放锁线程条件等待
notify()唤醒一个等待线程1唤醒单个线程
notifyAll()唤醒所有等待线程全部唤醒所有线程

5. 注意事项

  1. 必须在同步代码块中使用
    • wait()notify() 和 notifyAll() 必须在 synchronized 代码块或方法中调用,否则会抛出 IllegalMonitorStateException
  2. 条件检查
    • 使用 wait() 时,通常需要在 while 循环中检查条件,而不是 if,以避免虚假唤醒(spurious wakeup)。
  3. 锁的竞争
    • 被唤醒的线程需要重新竞争锁,因此可能会存在竞争问题。
  4. 中断处理
    • wait() 方法可能会抛出 InterruptedException,需要妥善处理中断。

6. 示例:生产者-消费者模型

class SharedResource {
    private int value;
    private boolean available = false;

    public synchronized void produce(int newValue) {
        while (available) {
            try {
                wait(); // 等待消费者消费
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        value = newValue;
        available = true;
        notifyAll(); // 唤醒所有消费者
    }

    public synchronized int consume() {
        while (!available) {
            try {
                wait(); // 等待生产者生产
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        available = false;
        notifyAll(); // 唤醒所有生产者
        return value;
    }
}

7. 总结

  • wait()notify() 和 notifyAll() 是 Java 中实现线程间通信的核心方法。
  • 它们必须在同步代码块中使用,且通常与条件检查结合使用。
  • wait() 用于线程等待,notify() 用于唤醒单个线程,notifyAll() 用于唤醒所有线程。
  • 适用于生产者-消费者模型、线程池任务调度等场景。
THE END
点赞13 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容