JUC Condition 详解及常用代码展示
一、Condition 概述
Condition 是 Java 并发包(JUC)中用于线程间协调的核心接口,它提供了类似 Object.wait()
和 Object.notify()
的功能,但更加强大和灵活。Condition 必须与 Lock 配合使用,主要特点包括:
- 多条件队列:一个 Lock 可以关联多个 Condition
- 精确唤醒:可以选择性唤醒特定条件上的线程
- 超时机制:支持带超时的等待操作
- 中断响应:支持中断的等待操作
二、Condition 核心方法
方法 | 描述 |
---|---|
await() | 使当前线程等待,直到被通知或中断 |
awaitUninterruptibly() | 不可中断的等待 |
awaitNanos(long) | 等待指定纳秒时间 |
await(long, TimeUnit) | 等待指定时间 |
signal() | 唤醒一个等待线程 |
signalAll() | 唤醒所有等待线程 |
三、Condition 实现原理
1. 数据结构(基于 AQS)
2. await 流程
3. signal 流程
四、源码解析(基于 ReentrantLock 的实现)
1. Condition 实现类(AbstractQueuedSynchronizer.ConditionObject)
public class ConditionObject implements Condition {
// 条件队列头节点
private transient Node firstWaiter;
// 条件队列尾节点
private transient Node lastWaiter;
// await 方法实现
public final void await() throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
// 1. 创建节点加入条件队列
Node node = addConditionWaiter();
// 2. 完全释放锁
int savedState = fullyRelease(node);
// 3. 阻塞等待
while (!isOnSyncQueue(node)) {
LockSupport.park(this);
if (Thread.interrupted())
break;
}
// 4. 重新获取锁
if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
interruptMode = REINTERRUPT;
}
// signal 方法实现
public final void signal() {
if (!isHeldExclusively())
throw new IllegalMonitorStateException();
Node first = firstWaiter;
if (first != null)
doSignal(first);
}
private void doSignal(Node first) {
do {
if ((firstWaiter = first.nextWaiter) == null)
lastWaiter = null;
first.nextWaiter = null;
} while (!transferForSignal(first) &&
(first = firstWaiter) != null);
}
}
2. 关键数据结构(AQS Node)
static final class Node {
// 节点状态
volatile int waitStatus;
// 同步队列链接
volatile Node prev;
volatile Node next;
// 条件队列链接
Node nextWaiter;
// 关联线程
volatile Thread thread;
// 模式标识
static final Node SHARED = new Node();
static final Node EXCLUSIVE = null;
// 等待状态值
static final int CANCELLED = 1;
static final int SIGNAL = -1;
static final int CONDITION = -2;
}
五、常用代码示例
1. 生产者-消费者模型
import java.util.concurrent.locks.*;
class BoundedBuffer {
final Lock lock = new ReentrantLock();
final Condition notFull = lock.newCondition();
final Condition notEmpty = lock.newCondition();
final Object[] items = new Object[100];
int putptr, takeptr, count;
public void put(Object x) throws InterruptedException {
lock.lock();
try {
// 缓冲区满时等待
while (count == items.length)
notFull.await();
items[putptr] = x;
if (++putptr == items.length) putptr = 0;
++count;
// 唤醒消费者
notEmpty.signal();
} finally {
lock.unlock();
}
}
public Object take() throws InterruptedException {
lock.lock();
try {
// 缓冲区空时等待
while (count == 0)
notEmpty.await();
Object x = items[takeptr];
if (++takeptr == items.length) takeptr = 0;
--count;
// 唤醒生产者
notFull.signal();
return x;
} finally {
lock.unlock();
}
}
}
2. 多条件精确唤醒
class TaskProcessor {
private final Lock lock = new ReentrantLock();
private final Condition taskACondition = lock.newCondition();
private final Condition taskBCondition = lock.newCondition();
private boolean taskAReady = false;
private boolean taskBReady = false;
public void prepareTaskA() {
lock.lock();
try {
taskAReady = true;
taskACondition.signalAll();
} finally {
lock.unlock();
}
}
public void prepareTaskB() {
lock.lock();
try {
taskBReady = true;
taskBCondition.signalAll();
} finally {
lock.unlock();
}
}
public void processTaskA() throws InterruptedException {
lock.lock();
try {
while (!taskAReady) {
taskACondition.await();
}
// 执行任务A
System.out.println("Processing Task A");
taskAReady = false;
} finally {
lock.unlock();
}
}
public void processTaskB() throws InterruptedException {
lock.lock();
try {
while (!taskBReady) {
taskBCondition.await();
}
// 执行任务B
System.out.println("Processing Task B");
taskBReady = false;
} finally {
lock.unlock();
}
}
}
3. 超时等待控制
public class TimeoutTask {
private final Lock lock = new ReentrantLock();
private final Condition condition = lock.newCondition();
private boolean conditionMet = false;
public void performTask() throws InterruptedException {
lock.lock();
try {
// 等待5秒超时
long nanosTimeout = TimeUnit.SECONDS.toNanos(5);
while (!conditionMet) {
if (nanosTimeout <= 0L) {
System.out.println("Timeout occurred!");
return;
}
nanosTimeout = condition.awaitNanos(nanosTimeout);
}
// 条件满足后执行任务
System.out.println("Condition met, performing task");
} finally {
lock.unlock();
}
}
public void setCondition() {
lock.lock();
try {
conditionMet = true;
condition.signal();
} finally {
lock.unlock();
}
}
}
4. 不可中断等待
public class UninterruptibleTask {
private final Lock lock = new ReentrantLock();
private final Condition condition = lock.newCondition();
public void execute() {
lock.lock();
try {
// 不可中断等待
condition.awaitUninterruptibly();
System.out.println("Resumed after waiting");
} finally {
lock.unlock();
}
}
public void resume() {
lock.lock();
try {
condition.signal();
} finally {
lock.unlock();
}
}
}
六、Condition 最佳实践
-
始终在循环中检查条件
while (!condition) { cond.await(); }
-
使用 try-finally 确保锁释放
lock.lock(); try { // 临界区操作 } finally { lock.unlock(); }
-
合理选择唤醒方法
signal()
:唤醒一个线程(更高效)signalAll()
:唤醒所有线程(避免饥饿)
-
考虑使用超时机制
if (condition.await(5, TimeUnit.SECONDS)) { // 条件满足 } else { // 超时处理 }
-
避免信号丢失
// 错误示例: if (condition) { cond.signal(); // 可能丢失信号 } // 正确做法: condition = true; cond.signal();
七、Condition 与 Object 监视器对比
特性 | Condition | Object 监视器 |
---|---|---|
多条件队列 | ✅ 支持 | ❌ 不支持 |
精确唤醒 | ✅ 支持 | ❌ 只能随机或全部唤醒 |
超时控制 | ✅ 纳秒级 | ✅ 毫秒级 |
中断响应 | ✅ 支持 | ✅ 支持 |
锁绑定 | 必须绑定 Lock | 与 synchronized 绑定 |
使用范式 | lock.lock(); try { ... } finally { lock.unlock(); } | synchronized(monitor) { ... } |
八、常见问题解决方案
1. 处理虚假唤醒
// 使用 while 循环而非 if 判断
while (!resourceAvailable) {
condition.await();
}
2. 避免死锁
// 确保锁的释放顺序与获取顺序一致
public void transfer(Account from, Account to, int amount) {
Account first = from.getId() < to.getId() ? from : to;
Account second = first == from ? to : from;
first.lock.lock();
try {
second.lock.lock();
try {
// 转账操作
} finally {
second.lock.unlock();
}
} finally {
first.lock.unlock();
}
}
3. 性能优化
// 使用信号而不是广播
public void dataChanged() {
lock.lock();
try {
// 只唤醒一个等待线程
condition.signal();
} finally {
lock.unlock();
}
}
九、高级应用场景
1. 线程池任务协调
class AdvancedThreadPool {
private final Lock lock = new ReentrantLock();
private final Condition hasTask = lock.newCondition();
private final Condition poolFull = lock.newCondition();
public void submitTask(Runnable task) throws InterruptedException {
lock.lock();
try {
while (poolIsFull()) {
poolFull.await();
}
// 添加任务
hasTask.signal();
} finally {
lock.unlock();
}
}
public Runnable getTask() throws InterruptedException {
lock.lock();
try {
while (noTasksAvailable()) {
hasTask.await();
}
// 获取任务
poolFull.signal();
return nextTask();
} finally {
lock.unlock();
}
}
}
2. 多阶段任务处理
class MultiStageProcessor {
private final Lock lock = new ReentrantLock();
private final Condition stage1Complete = lock.newCondition();
private final Condition stage2Complete = lock.newCondition();
public void stage1() throws InterruptedException {
lock.lock();
try {
// 执行阶段1任务
stage1Complete.signalAll();
} finally {
lock.unlock();
}
}
public void stage2() throws InterruptedException {
lock.lock();
try {
while (!stage1Done) {
stage1Complete.await();
}
// 执行阶段2任务
stage2Complete.signalAll();
} finally {
lock.unlock();
}
}
public void stage3() throws InterruptedException {
lock.lock();
try {
while (!stage2Done) {
stage2Complete.await();
}
// 执行阶段3任务
} finally {
lock.unlock();
}
}
}
总结
Condition 是 JUC 中强大的线程协调工具,相比传统的 wait/notify 机制,它提供了:
- 更精细的控制:多条件队列支持
- 更安全的操作:与 Lock 集成,避免监视器锁的缺陷
- 更灵活的使用:支持超时和不可中断等待
- 更高效的唤醒:精确唤醒特定条件的线程
正确使用 Condition 的关键点:
- 始终在 while 循环中检查条件
- 使用 try-finally 确保锁释放
- 合理选择 signal 和 signalAll
- 考虑使用超时机制避免永久阻塞
- 注意信号丢失和虚假唤醒问题
通过 Condition,开发者可以构建更高效、更可靠的并发程序,特别适合实现生产者-消费者模式、任务协调、资源池管理等复杂并发场景。