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

在Java中,wait()notify() 和 notifyAll() 方法是用于线程间通信的关键方法,它们都定义在 Object 类中,并且必须与同步机制(如 synchronized 方法或代码块)一起使用。这些方法允许线程安全地等待某些条件成立或者通知其他等待该条件的线程条件已经发生变化。

1. wait()

  • 作用:使当前正在执行的线程等待,直到其他线程调用同一个对象上的 notify() 或 notifyAll() 方法来唤醒它。
  • 特点
    • 调用 wait() 的线程会释放对该对象的锁,并进入“等待”状态。
    • 只有当另一个线程调用了相同对象的 notify() 或 notifyAll() 方法时,该线程才可能被重新激活并继续执行。
    • 如果没有其他线程调用 notify() 或 notifyAll(),那么即使过了指定的时间(如果指定了超时),该线程也不会自动恢复执行。
  • 重载形式
    • wait():无限期等待,直到其他线程调用 notify() 或 notifyAll()
    • wait(long timeout):带有超时参数,如果在指定时间内没有收到通知,则线程将自动恢复执行。
    • wait(long timeout, int nanos):更加精确的超时等待,支持纳秒级精度。

2. notify()

  • 作用:随机唤醒一个正在等待该对象监视器的单个线程。如果有多个线程都在等待这个对象的锁,notify() 只会选择其中一个进行唤醒。
  • 注意:不能保证哪一个线程会被选中唤醒,这取决于具体的实现细节。
  • 使用场景:当你只需要唤醒一个等待中的线程时使用。

3. notifyAll()

  • 作用:唤醒所有正在等待该对象监视器的线程。不过,虽然所有的线程都会被唤醒,但只有一个线程能够获得对象的锁并继续执行,其余的线程将再次进入等待状态。
  • 使用场景:当你不确定哪个线程需要首先被唤醒,或者当多个线程都需要对某个变化做出响应时使用。

使用规则

  • 这些方法只能在同步上下文中调用,即要么在同步方法内,要么在同步代码块中。否则会抛出 IllegalMonitorStateException 异常。
  • 当一个线程调用 wait() 方法后,它会释放所持有的对象锁,以便其他线程可以获得该锁并修改对象的状态。
  • 调用 notify() 或 notifyAll() 方法的线程不会立即释放锁;锁只会在退出同步方法或同步代码块时才被释放。

示例

public class Example {
    private final Object lock = new Object();
    private boolean condition = false;

    public void waitForCondition() throws InterruptedException {
        synchronized (lock) {
            while (!condition) {
                lock.wait(); // 等待条件变为true
            }
            // 条件满足后的操作
        }
    }

    public void changeCondition() {
        synchronized (lock) {
            condition = true;
            lock.notifyAll(); // 通知所有等待的线程条件已改变
        }
    }
}

在这个例子中,waitForCondition() 方法会让调用它的线程等待,直到 changeCondition() 方法改变了共享变量 condition 的值,并通过 notifyAll() 方法通知所有等待的线程检查条件是否满足。这种方法确保了线程间的协调和有效的资源共享。

THE END
喜欢就支持一下吧
点赞11 分享