synchronized 与 Object.wait() 的锁释放天然原子绑定,JVM 强制保证调用 wait() 时立即不可分割地释放当前 monitor 锁并进入等待;必须在 synchronized 块内调用,且只释放当前同步对象的锁,唤醒后须重新竞争该锁才能继续执行。

Java 中 synchronized 与 Object.wait() 的锁释放是**天然原子绑定的**,不需要手动干预或额外同步机制。这种原子性由 JVM 规范强制保证:线程在调用 wait() 的瞬间,会**立即、不可分割地**释放当前持有的 monitor 锁,并进入等待状态。
为什么是原子的?
JVM 在执行 wait() 时,底层会将“释放锁”和“挂起线程”两个动作合并为一个原子操作。操作系统层面不会让其他线程在这之间抢到该锁,也不会出现线程已释放锁但尚未进入 WAITING 状态的中间态。这是 Java 内存模型(JMM)对 monitor 的语义要求,不是实现细节,而是必须遵守的行为契约。
必须在 synchronized 块/方法内调用 wait()
否则会抛出 IllegalMonitorStateException。因为 wait() 只能作用于当前线程正持有的锁对象:
- 调用
obj.wait()前,线程必须已通过synchronized(obj)获取了obj的 monitor 锁; - JVM 会在进入
wait()时校验持有关系,不满足则直接拒绝; - 这确保了“释放锁”动作有明确的锁目标,也避免了无锁调用导致的状态混乱。
wait() 释放的是哪个锁?
只释放当前 synchronized 作用的对象锁,且仅释放这一把:
立即学习“Java免费学习笔记(深入)”;
- 如果同步块是
synchronized(this),this.wait()释放的是this的锁; - 如果同步块是
synchronized(lockObj),必须调用lockObj.wait(),不能写成this.wait(); - 一个线程可持有多个锁,但
wait()只影响它正在调用的那一个对象的锁,其余锁不受影响。
唤醒后如何重新获取锁?
wait() 返回前,线程必须**重新竞争并获得同一把锁**,才能继续执行:
- 被
notify()或interrupt()唤醒后,线程进入锁的争用队列(Entry Set),不是直接运行; - 只有成功获取锁后,才会从
wait()方法返回,继续执行后续代码; - 这意味着
wait()的整个生命周期——释放锁 → 等待 → 争锁 → 持锁返回——天然串行化,无需额外保护。
这个设计让 wait/notify 成为构建条件等待(condition waiting)的基础,比如生产者-消费者中的“缓冲区非空”或“缓冲区未满”判断,都依赖这套原子释放+重入机制来保证线程安全。


















