condition 是 reentrantlock 的配套工具,支持多等待队列和精准唤醒;一个锁可创建多个 condition 实例,各管理独立 fifo 队列,需配合 lock/unlock 使用 while 循环判断条件,优先用 signal() 实现高效线程调度。

Condition 是 ReentrantLock 的配套工具,它让线程能按具体业务条件等待和唤醒,避免了 synchronized + wait/notify 的“全唤醒”问题,从而实现比传统 wait 更精准的唤醒控制。
Condition 的核心优势:绑定多个等待队列
synchronized 只有一个内置锁对象,所有 wait() 都共用同一个等待队列,notify() 只能随机唤醒或 notifyAll() 全部唤醒。而一个 ReentrantLock 可以创建多个 Condition 实例,每个 Condition 管理独立的等待队列。比如生产者-消费者场景中,可以分别定义 notFull 和 notEmpty 两个 Condition,让满时只唤醒消费者、空时只唤醒生产者。
- 每个 Condition 对应一个 FIFO 等待队列,互不干扰
- await() 使当前线程进入该 Condition 的队列并释放锁;signal() 唤醒该队列头部的一个线程
- 不会误唤醒其他业务逻辑相关的线程(如库存充足时不该唤醒补货线程)
正确使用 Condition 的三步关键操作
Condition 不是独立存在,必须与 ReentrantLock 配合,并严格遵循“加锁 → 判断条件 → await/signal → 解锁”流程。漏掉任何一环都可能引发死锁或虚假唤醒。
Java JDK 25 来自 OpenJDK 官方归档,版本为 JDK 25,本条下载地址已指向官方 Windows x64 zip 安装包直链,适合调试旧项目或兼容旧版 Java 运行环境。
- 必须在 lock() 之后、条件判断之前获取 Condition 实例(不能提前缓存,否则可能关联错误锁)
- 条件判断要用 while 而非 if:防止虚假唤醒或被 signal 后条件仍不满足,需重新检查
- await() 前已持有锁,调用后自动释放;被 signal 唤醒后会重新竞争锁,成功获取后才从 await() 返回
典型场景示例:双条件队列的阻塞队列
下面是一个简化版的有界队列,用两个 Condition 分别管理“非满”和“非空”状态:
private final ReentrantLock lock = new ReentrantLock();
private final Condition notFull = lock.newCondition();
private final Condition notEmpty = lock.newCondition();
private final List<integer> queue = new ArrayList();
public void put(int item) throws InterruptedException {
lock.lock();
try {
while (queue.size() == capacity) {
notFull.await(); // 等待“非满”条件
}
queue.add(item);
notEmpty.signal(); // 有新元素,通知消费者
} finally {
lock.unlock();
}
}
public int take() throws InterruptedException {
lock.lock();
try {
while (queue.isEmpty()) {
notEmpty.await(); // 等待“非空”条件
}
int item = queue.remove(0);
notFull.signal(); // 拿走一个,通知生产者可继续放
return item;
} finally {
lock.unlock();
}
}</integer>
这里 notFull.signal() 和 notEmpty.signal() 各自只唤醒对应等待队列中的线程,完全规避了 notifyAll() 带来的无效调度和竞争开销。
注意 signal() 与 signalAll() 的选择
signal() 唤醒单个等待线程,适合大多数精确匹配场景;signalAll() 唤醒全部,适用于条件变更影响所有等待者(如关闭标志置位)。但要注意:即使 signal() 唤醒一个线程,它也需要重新获取锁并再次检查条件——所以无需担心“唤醒错人”,只要条件判断逻辑正确,就能自然过滤掉不满足的线程。
- 优先用 signal(),减少上下文切换和锁竞争
- 避免在未持有锁时调用 signal(),会抛 IllegalMonitorStateException
- signal() 不保证唤醒顺序,但 Condition 内部队列是 FIFO,实际行为可预期
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










