Java中的wait和notify机制
基础概念
在Java中,wait()和notify()是Object类的原生方法,用于实现线程间的协作:
wait()- 使当前线程释放对象锁并进入等待状态
- 必须在
synchronized代码块内调用 - 语法:
obj.wait()或obj.wait(long timeout) - 线程状态变化:RUNNING → WAITING
notify()- 随机唤醒一个在该对象上等待的线程
notifyAll()唤醒所有等待线程- 同样必须在
synchronized代码块内调用
// 生产者-消费者示例
class Buffer {private int data;private boolean available = false;public synchronized void produce(int value) {while (available) wait(); // 等待消费者取走数据data = value;available = true;notifyAll(); // 唤醒消费者}public synchronized int consume() {while (!available) wait(); // 等待生产者写入数据available = false;notifyAll(); // 唤醒生产者return data;}
}
执行流程
graph LRA[线程调用wait] --> B[释放对象锁]B --> C[进入等待队列]D[其他线程调用notify] --> E[唤醒等待线程]E --> F[线程尝试重新获取锁]F --> G[获取锁后继续执行]
Condition接口(java.util.concurrent.locks)
核心方法
Condition接口提供了更灵活的线程协调机制,需配合Lock使用:
await()- 功能类似
wait(),但支持更丰富的等待条件 - 可响应中断:
awaitUninterruptibly() - 支持超时:
await(long time, TimeUnit unit)
- 功能类似
signal()- 唤醒单个等待线程(类似
notify()) signalAll()唤醒所有等待线程
- 唤醒单个等待线程(类似
使用示例
import java.util.concurrent.locks.*;class ConditionExample {private final Lock lock = new ReentrantLock();private final Condition notFull = lock.newCondition();private final Condition notEmpty = lock.newCondition();private int[] buffer = new int[10];private int count = 0;public void produce(int item) throws InterruptedException {lock.lock();try {while (count == buffer.length) notFull.await(); // 缓冲区满时等待buffer[count++] = item;notEmpty.signal(); // 唤醒消费者} finally {lock.unlock();}}public int consume() throws InterruptedException {lock.lock();try {while (count == 0) notEmpty.await(); // 缓冲区空时等待int item = buffer[--count];notFull.signal(); // 唤醒生产者return item;} finally {lock.unlock();}}
}
对比分析
| 特性 | wait/notify | Condition |
|---|---|---|
| 锁机制 | 必须配合synchronized | 必须配合Lock实现 |
| 多条件等待 | 不支持 | 支持创建多个Condition实例 |
| 中断响应 | 仅基础中断 | 提供awaitUninterruptibly() |
| 超时控制 | 有限支持 | 精确到纳秒的超时控制 |
| 公平性 | 依赖synchronized | 可通过ReentrantLock配置 |
| 唤醒精确性 | notify随机唤醒 | signal可定向唤醒特定条件队列 |
最佳实践
循环检查条件
始终在循环中检查等待条件,避免虚假唤醒:while (!condition) {obj.wait(); }资源释放
使用try-finally确保锁释放:lock.lock(); try {// 临界区代码 } finally {lock.unlock(); }选择建议
- 简单场景:优先使用
synchronized+wait/notify - 复杂同步:使用
Lock+Condition(如多条件队列、公平锁需求)
- 简单场景:优先使用
注意:Java 5+推荐使用
java.util.concurrent包中的高级同步工具(如BlockingQueue),仅在底层控制需要时使用wait/notify或Condition。