wait 和 notify 为什么要放在 synchronized 代码块中?

705 阅读4分钟

Hi 大家好,我是 DHL,大厂程序员,公众号:ByteCode ,在美团、快手、小米工作过。搞过逆向,做过性能优化,研究过系统,擅长鸿蒙、Android、Kotlin、性能优化、职场分享。

来自微信小程序「猿面试」每日分享一道大厂面试题,涉及 JavaAndroid鸿蒙和ArkTS设计模式算法和数据结构 等内容。


wait 和 notify 为什么要放在 synchronized 代码块中?

wait()notify() / notifyAll() 是 Java 中用于线程间通信的方法,它们必须在 synchronized 代码块或方法中使用,原因主要有以下几点:

监视器规则

Java 规定,wait()notify() 必须在拥有对象监视器的线程中调用。换句话说,调用这些方法的线程必须首先获得对象的锁(通过 synchronized)。

如果线程没有持有对象的锁,调用 wait() 将会抛出 IllegalMonitorStateException 异常,因此,必须在同步代码块中调用这些方法,以确保当前线程持有正确的锁

线程安全

wait()notify() 必然是成对出现的,如果一个线程被 wait() 方法阻塞,那么必然需要通过 notify() 方法来唤醒这个被阻塞的线程,从而实现多线程之间的通信。

因此需要保证 wait()notify() 操作需要保证原子性,即在同一时刻只能有一个线程执行这些操作。synchronized 关键字确保了这一点,因为它会锁定对象或类的监视器,防止多个线程同时进入临界区。

如果不在同步代码块中,多个线程可能会同时调用 wait()notify(),导致不可预测的行为和数据不一致。

避免 lost wake up 问题

Java 强制要求 wait()notify() 必须在同步块中调用,以避免 lost wake up 问题。这种问题发生在多个线程竞争同一个锁时,可能会导致某些线程的唤醒信号丢失。

锁的管理:

wait()notify() 方法需要操作对象的监视器锁(monitor lock)。

当一个线程调用 wait() 方法时,它会释放当前持有的监视器锁,并进入等待状态,直到其他线程调用 notify()notifyAll() 方法来唤醒它。

同样,notify()notifyAll() 方法也会释放监视器锁,以便等待的线程可以重新获取锁并继续执行。

因此,这些方法必须在同步代码块中调用,以确保线程能够正确地获取和释放锁。

示例代码

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

    public void doSomething() {
        synchronized (lock) {
            try {
                while (/* condition not met */) {
                    lock.wait(); // 等待条件满足
                }
                // 执行相关操作
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
    }

    public void notifySomething() {
        synchronized (lock) {
            // 修改条件
            lock.notifyAll(); // 通知等待的线程
        }
    }
}

总结

wait()notify() 放在 synchronized 代码块中是为了确保线程安全、遵循监视器规则、避免死锁。

更多大厂面试题,欢迎前往微信搜索小程序 「猿面试」 查看。微信小程序 (猿面试) 包含了 Java、Android、鸿蒙和ArkTS设计模式算法和数据结构 相关内容,

Hi 大家好,我是 DHL,大厂程序员,公众号:ByteCode ,在美团、快手、小米工作过。搞过逆向,做过性能优化,研究过系统,擅长鸿蒙、Android、Kotlin、性能优化、职场分享。

更多面试题

开源新项目

  • 云同步编译工具(SyncKit),本地写代码,远程编译,欢迎前去查看 SyncKit

  • KtKit 小巧而实用,用 Kotlin 语言编写的工具库,欢迎前去查看 KtKit

  • 最全、最新的 AndroidX Jetpack 相关组件的实战项目以及相关组件原理分析文章,正在逐渐增加 Jetpack 新成员,仓库持续更新,欢迎前去查看 AndroidX-Jetpack-Practice

  • LeetCode / 剑指 offer,包含多种解题思路、时间复杂度、空间复杂度分析,在线阅读