当前位置: 面试刷题>> Java 中的 wait、notify 和 notifyAll 方法有什么作用?


在Java多线程编程中,`wait`、`notify`和`notifyAll`方法是实现线程间通信的重要机制,它们与对象的监视器(monitor)锁紧密相关。这些方法定义在`Object`类中,意味着Java中的任何对象都可以作为锁以及线程间通信的媒介。理解并正确运用这些方法对于设计高效、可靠的并发程序至关重要。 ### wait 方法 `wait`方法用于使当前线程等待,直到其他线程调用此对象的`notify`方法或`notifyAll`方法,或者等待时间到了指定的毫秒数。调用`wait`方法的前提是当前线程必须持有该对象的监视器锁。调用`wait`方法后,当前线程会释放该对象的监视器锁,并进入等待状态,直到其他线程调用`notify`或`notifyAll`方法唤醒它,或者等待超时。 **示例代码**: ```java public class WaitExample { private final Object lock = new Object(); private boolean ready = false; public void waitForReady() throws InterruptedException { synchronized (lock) { while (!ready) { lock.wait(); // 等待ready条件成立 } // 当ready为true时,继续执行后续操作 } } public void setReady() { synchronized (lock) { ready = true; lock.notify(); // 唤醒等待的线程 } } } ``` ### notify 方法 `notify`方法用于唤醒正在等待该对象监视器锁的单个线程。如果有多个线程在等待,选择哪个线程被唤醒是不确定的。重要的是,`notify`不会立即释放锁,而是在执行完`notify`方法所在的同步代码块之后,由JVM决定哪个等待的线程将获得锁并继续执行。 ### notifyAll 方法 与`notify`方法不同,`notifyAll`方法会唤醒所有等待该对象监视器锁的线程。这些线程将竞争获取该对象的锁,只有成功获取锁的线程才能继续执行。 **选择notify或notifyAll**: - 如果只需要唤醒一个线程,且你确切知道哪个线程应该被唤醒(尽管这在实践中很少),可以使用`notify`。 - 如果需要唤醒所有等待的线程,或者你不确定哪个线程应该被唤醒,应使用`notifyAll`。这通常更安全,因为可以避免因不确定唤醒哪个线程而导致的逻辑错误或死锁。 ### 注意事项 - `wait`、`notify`和`notifyAll`必须在同步代码块或同步方法中调用,因为调用这些方法的线程必须持有对象的监视器锁。 - 调用`wait`、`notify`和`notifyAll`方法时,如果当前线程未持有该对象的锁,则会抛出`IllegalMonitorStateException`。 - `wait`可以指定等待时间,如果在指定时间内没有被唤醒,则自动返回。 - 唤醒的线程会重新尝试获取锁,如果此时锁被其他线程持有,则等待锁释放。 ### 总结 `wait`、`notify`和`notifyAll`是Java中处理线程间通信的重要工具,它们允许线程在特定条件下等待或唤醒其他线程。正确使用这些方法,结合合理的同步控制,可以设计出高效、可靠的并发程序。在实际开发中,务必注意避免死锁、活锁以及竞态条件等问题,确保程序的稳定性和性能。在深入理解这些概念的基础上,结合具体的业务场景,选择最合适的同步和通信机制,是成为一名高级程序员的关键步骤之一。在“码小课”网站上,你可以找到更多关于Java并发编程的深入解析和实战案例,帮助你进一步提升编程技能。
推荐面试题