一、Condition机制的核心原理
-
1. 定位与优势
Condition是Java 1.5引入的显式锁(Lock)配套机制,用于替代传统的Object.wait()/notify(),提供更精细的线程控制能力:-
• 多条件队列:一个Lock可关联多个Condition(如生产者消费者模型中的"非满"、"非空"条件)
-
• 灵活唤醒:支持
signal()(唤醒单个)和signalAll()(唤醒全部) -
• 增强控制:提供超时等待(
awaitNanos())、不可中断等待(awaitUninterruptibly())等扩展
-
-
2. 底层实现机制
Condition基于AQS(AbstractQueuedSynchronizer)实现:-
• 条件队列:每个Condition维护独立的FIFO等待队列(与AQS同步队列分离)
- • await()流程:
-
• signal()流程:将条件队列的头节点转移到AQS同步队列参与锁竞争
-
二、核心方法与使用规范
▶ 关键方法
|
方法 |
作用 |
注意点 |
await() |
释放锁并阻塞 |
需在 |
signal() |
唤醒单个等待线程 |
优先选择最长等待者 |
signalAll() |
唤醒所有等待线程 |
避免信号丢失但可能引发竞争 |
▶ 强制规范(违反将报错)
- 1. 锁持有要求
调用await()/signal()/signalAll()前必须持有关联的Lock锁,否则抛出IllegalMonitorStateExceptionlock.lock(); // 必须先获取锁 try { condition.await(); } finally { lock.unlock(); } - 2. 条件检查范式
必须使用while循环而非if检查条件,防止 虚假唤醒(Spurious Wakeup):while (条件不满足) { // 必须用while循环! condition.await(); }原因:底层操作系统可能导致线程无故唤醒
-
3. 中断处理
await()可能抛出InterruptedException,需在代码中明确处理中断逻辑
三、使用实例详解
实例1:生产者-消费者模型(单Condition版)
import java.util.concurrent.locks.*;
publicclassProducerConsumerDemo {
privatefinalLocklock=newReentrantLock();
privatefinalConditionnotFull= lock.newCondition(); // 队列非满条件
privatefinal Queue<Integer> queue = newLinkedList<>();
privatefinalintCAPACITY=10;
// 生产者
publicvoidproduce(int item)throws InterruptedException {
lock.lock();
try {
while (queue.size() == CAPACITY) {
System.out.println("队列已满,生产者等待");
notFull.await(); // 释放锁并阻塞
}
queue.offer(item);
System.out.println("生产: " + item);
notFull.signalAll(); // 唤醒所有等待线程
} finally {
lock.unlock();
}
}
// 消费者
publicvoidconsume()throws InterruptedException {
lock.lock();
try {
while (queue.isEmpty()) {
System.out.println("队列为空,消费者等待");
notFull.await(); // 使用同一个条件
}
intitem= queue.poll();
System.out.println("消费: " + item);
notFull.signalAll(); // 唤醒生产者
} finally {
lock.unlock();
}
}
}
缺陷:生产者可能唤醒其他生产者,存在无效竞争
实例2:精准唤醒(多Condition版)
class PrecisionWakeupDemo {
privatefinalLocklock=newReentrantLock();
privatefinalConditionconditionA= lock.newCondition();
privatefinalConditionconditionB= lock.newCondition();
privateintflag=1; // 1:执行A 2:执行B
publicvoidtaskA()throws InterruptedException {
lock.lock();
try {
while (flag != 1) {
conditionA.await(); // 仅等待条件A
}
System.out.println("执行A任务");
flag = 2;
conditionB.signal(); // 精准唤醒B
} finally {
lock.unlock();
}
}
publicvoidtaskB()throws InterruptedException {
lock.lock();
try {
while (flag != 2) {
conditionB.await(); // 仅等待条件B
}
System.out.println("执行B任务");
flag = 1;
conditionA.signal(); // 精准唤醒A
} finally {
lock.unlock();
}
}
}
优势:避免无效线程唤醒,显著提升性能
四、与传统机制对比
|
特性 |
synchronized + wait/notify |
Lock + Condition |
|
锁获取方式 |
隐式(JVM管理) |
显式(代码控制) |
|
条件变量数量 |
1个(Object监视器) |
多个(可自定义) |
|
超时控制 |
有限支持 |
支持 |
|
中断响应 |
仅抛异常 |
支持不可中断模式 |
|
唤醒精度 |
只能全部唤醒( |
可精准唤醒指定条件队列 |
五、工程实践建议
-
1. 优先使用
signal()
在明确唤醒目标时使用signal()减少竞争,不确定时用signalAll() -
2. 避免嵌套调用
禁止在Condition等待中嵌套调用其他锁操作,防止死锁 -
3. 性能敏感场景选Condition
高并发队列(如ArrayBlockingQueue)底层采用Condition实现 -
4. 监控工具支持
使用jstack或JProfiler可查看Condition等待队列状态
1643

被折叠的 条评论
为什么被折叠?



