You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java并发疑问:wait()与notify()为何需置于synchronized块中?

Java中wait()/notify()的核心疑问解答

嘿,这个问题绝对是Java并发入门里最容易卡壳的点之一,我来给你拆解明白~

先搞懂:为什么必须把wait()/notify()放在synchronized块里?

本质上是为了避免竞态条件,保证线程间状态的一致性。咱们拿你说的线程A和线程B的场景来举例:

假设线程A要等待某个条件(比如共享队列为空,需要等线程B放元素),如果没有synchronized保护,流程可能变成这样:

  1. 线程A检查队列,发现是空的
  2. 就在线程A准备调用wait()的瞬间,CPU切换到线程B,线程B往队列里放了元素,然后调用了notify()
  3. 这时候线程A才执行wait(),但它已经错过了刚才的notify,会一直阻塞下去——这就是典型的竞态条件,因为检查条件和wait()不是原子操作。

而synchronized块的作用,就是把“检查条件 + 调用wait()”或者“修改条件 + 调用notify()”变成一个原子操作:

  • 线程A必须先获取锁,才能检查条件和调用wait(),这时候线程B根本没法修改条件,直到线程A调用wait()自动释放锁
  • 线程B必须先获取同一个锁,才能修改条件和调用notify(),这时候线程A要么在wait(没持有锁),要么已经执行完了,不会出现刚才的“错过通知”情况

另外还有个关键:wait()调用时会自动释放锁,notify()调用后不会立刻释放锁——只有退出synchronized块才会释放。这也要求你必须先持有锁(也就是在synchronized块里),才能调用这两个方法,不然JVM会直接抛IllegalMonitorStateException。

再看:notify()到底该怎么执行?

其实notify()的执行逻辑和wait()是配套的,咱们还是用生产者消费者的代码例子来说明:

// 共享队列作为锁对象
class SharedQueue {
    private final Queue<String> queue = new LinkedList<>();
    private static final int MAX_CAPACITY = 3;

    // 生产者方法
    public synchronized void addItem(String item) throws InterruptedException {
        // 用while循环检查条件,防止虚假唤醒
        while (queue.size() == MAX_CAPACITY) {
            wait(); // 释放锁,进入阻塞状态
        }
        queue.add(item);
        System.out.println("生产者放入:" + item);
        notify(); // 唤醒一个在该锁上等待的线程
    }

    // 消费者方法
    public synchronized String takeItem() throws InterruptedException {
        while (queue.isEmpty()) {
            wait();
        }
        String item = queue.poll();
        System.out.println("消费者取出:" + item);
        notify();
        return item;
    }
}

notify()的执行步骤是这样的:

  1. 线程B(比如生产者)必须先获取锁对象的synchronized锁(也就是进入synchronized方法/块)
  2. 修改共享状态(比如往队列里加元素),让等待的线程A(消费者)的条件不再成立
  3. 调用notify():这会唤醒一个在该锁对象上wait的线程(可能是线程A,也可能是其他等待的线程,取决于JVM调度)
  4. 线程B继续执行synchronized块里的剩余代码,直到退出块,才会释放锁
  5. 被唤醒的线程A不会立刻执行,它会进入锁的等待队列,等获取到锁之后,才会从wait()的位置继续执行,并且必须重新检查条件(这就是为什么要用while而不是if,防止虚假唤醒——比如可能有其他线程又把队列填满了)

简单说:notify()只是“喊一声”,告诉等待的线程“条件可能变了”,但真正能继续执行,还得等当前线程释放锁,自己重新拿到锁才行。

内容的提问来源于stack exchange,提问作者DanielBK

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 09:57:10