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 LR
A[线程调用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。