ReentrantLock通过newCondition()创建多个独立Condition实例,每个对应专属等待队列,实现按业务条件精准唤醒;必须在持锁状态下使用await/signal,并配合while循环防虚假唤醒。

Java 中利用 ReentrantLock 的 newCondition() 创建多个等待队列,核心在于:每个 Condition 实例对应一个独立的等待队列,从而实现按条件精准唤醒,避免 Object.wait()/notify() 那种“全唤醒再判断”的低效和不确定性。
一个锁配多个 Condition,各管各的等待队列
ReentrantLock 本身只维护一个同步队列(用于争抢锁),但它支持创建任意多个 Condition 对象。每个 Condition 内部持有独立的等待队列(FIFO),线程调用其 await() 就进入该队列,调用 signal() 或 signalAll() 就只唤醒这个队列里的线程。
- 不是“锁有多个队列”,而是“一个锁 + 多个 Condition → 多个逻辑上分离的等待队列”
- 不同业务条件(如“缓冲区非空”“缓冲区非满”)应使用不同的
Condition实例 - 务必在持有锁的前提下创建和使用
Condition,否则抛IllegalMonitorStateException
典型场景:生产者-消费者中的双条件精准控制
以有界队列为例,需区分“队列空时消费者等待”和“队列满时生产者等待”。用两个 Condition 可彻底解耦:
class BoundedBuffer {
private final ReentrantLock lock = new ReentrantLock();
private final Condition notEmpty = lock.newCondition(); // 消费者等待队列
private final Condition notFull = lock.newCondition(); // 生产者等待队列
private final List<Object> buffer = new ArrayList<>();
private final int capacity;
BoundedBuffer(int capacity) { this.capacity = capacity; }
void put(Object item) throws InterruptedException {
lock.lock();
try {
while (buffer.size() == capacity)
notFull.await(); // 进入 notFull 队列等待
buffer.add(item);
notEmpty.signal(); // 只唤醒一个在 notEmpty 队列里等的消费者
} finally {
lock.unlock();
}
}
Object take() throws InterruptedException {
lock.lock();
try {
while (buffer.isEmpty())
notEmpty.await(); // 进入 notEmpty 队列等待
Object item = buffer.remove(0);
notFull.signal(); // 只唤醒一个在 notFull 队列里等的生产者
return item;
} finally {
lock.unlock();
}
}
}
关键细节与避坑点
精准唤醒依赖正确的条件判断和信号发送时机,常见错误包括:
立即学习“Java免费学习笔记(深入)”;
-
用错 Condition 调用 signal():比如消费者取完数据后调了
notEmpty.signal()是对的,但若误调notFull.signal()就会唤醒生产者,导致逻辑错乱 -
虚假唤醒未防护:
await()可能无故返回(spurious wakeup),必须用while循环重检条件,不能用if -
signal() vs signalAll():单个线程满足条件时用
signal()更高效;多个线程可能同时满足(如批量插入后多个消费者都可取)才用signalAll() -
Condition 必须由同一把锁创建:不同
ReentrantLock实例创建的Condition互不兼容,不能混用
扩展:更复杂的多等待队列场景
当业务需要按优先级、资源类型或状态分组等待时,可进一步拆分 Condition:
- 例如线程池中,区分“空闲工作线程等待任务”和“阻塞任务等待空闲线程”两个队列
- 数据库连接池中,分别管理“等待可用连接”和“等待归还连接完成”的线程
- 注意:Condition 数量不设限,但过多会增加内存开销和维护复杂度,按实际等待逻辑边界划分即可


















