1. 线程通信的基本原理
在多线程编程中,wait()和notify()是Java提供的线程间通信机制。这两个方法都定义在Object类中,这意味着任何Java对象都可以作为线程通信的载体。理解它们的工作机制,首先要明白Java对象头中的监视器(Monitor)概念。
每个Java对象都有一个内置锁(intrinsic lock)和等待队列。当线程调用对象的wait()方法时,它会释放锁并进入等待状态;notify()则用于唤醒等待队列中的线程。这种设计源于早期操作系统的管程(Monitor)概念,是解决并发问题的经典模式。
关键点:wait()和notify()本质上是基于对象监视器的底层操作,它们直接与对象的锁机制交互。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 同步块的必要性解析
2.1 竞态条件的预防
假设没有同步块保护,考虑以下场景:
- 线程A检查条件不满足,准备调用wait()
- 线程B此时修改了条件并调用notify()
- 线程A才真正执行wait()
这种情况下,线程A将永远等待,因为错过了唤醒信号。同步块通过原子性地执行"检查条件-执行等待"这一系列操作,避免了这种竞态条件。
java复制// 错误示例:无同步保护
if (!condition) {
obj.wait(); // 可能永远等待
}
// 正确用法
synchronized(obj) {
while (!condition) {
obj.wait();
}
}
2.2 锁状态的强制要求
从JVM实现层面看,wait()必须知道当前线程持有哪个对象的锁。当线程调用wait()时:
- JVM需要确认线程确实持有该对象的锁
- 需要记录锁的释放和后续重新获取
- 需要将线程放入正确的等待队列
这些操作都依赖于明确的同步上下文。如果没有同步块,JVM无法确定操作的目标锁对象,也无法保证操作的原子性。
3. 底层机制深度剖析
3.1 对象监视器结构
每个Java对象在内存中的布局包含:
- 对象头(Mark Word):存储锁状态、GC信息等
- 类元数据指针
- 实例数据
- 对齐填充
其中对象头中的锁标志位决定了对象的锁状态。wait()和notify()操作会修改这些标志位,
