JUC Condition 详解及常用代码展示

JUC Condition 详解及常用代码展示

一、Condition 概述

Condition 是 Java 并发包(JUC)中用于线程间协调的核心接口,它提供了类似 Object.wait()Object.notify() 的功能,但更加强大和灵活。Condition 必须与 Lock 配合使用,主要特点包括:

  1. 多条件队列:一个 Lock 可以关联多个 Condition
  2. 精确唤醒:可以选择性唤醒特定条件上的线程
  3. 超时机制:支持带超时的等待操作
  4. 中断响应:支持中断的等待操作

二、Condition 核心方法

方法描述
await()使当前线程等待,直到被通知或中断
awaitUninterruptibly()不可中断的等待
awaitNanos(long)等待指定纳秒时间
await(long, TimeUnit)等待指定时间
signal()唤醒一个等待线程
signalAll()唤醒所有等待线程

三、Condition 实现原理

1. 数据结构(基于 AQS)

Lock
Condition1
Condition2
等待队列
等待队列
AQS 同步队列
线程节点
线程节点

2. await 流程

线程ConditionLock获取锁调用 await()释放锁线程加入条件队列阻塞线程等待状态其他线程调用 signal()将线程转移到同步队列唤醒线程尝试重新获取锁线程ConditionLock

3. signal 流程

调用 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 最佳实践

  1. 始终在循环中检查条件

    while (!condition) {
        cond.await();
    }
    
  2. 使用 try-finally 确保锁释放

    lock.lock();
    try {
        // 临界区操作
    } finally {
        lock.unlock();
    }
    
  3. 合理选择唤醒方法

    • signal():唤醒一个线程(更高效)
    • signalAll():唤醒所有线程(避免饥饿)
  4. 考虑使用超时机制

    if (condition.await(5, TimeUnit.SECONDS)) {
        // 条件满足
    } else {
        // 超时处理
    }
    
  5. 避免信号丢失

    // 错误示例:
    if (condition) {
        cond.signal(); // 可能丢失信号
    }
    
    // 正确做法:
    condition = true;
    cond.signal();
    

七、Condition 与 Object 监视器对比

特性ConditionObject 监视器
多条件队列✅ 支持❌ 不支持
精确唤醒✅ 支持❌ 只能随机或全部唤醒
超时控制✅ 纳秒级✅ 毫秒级
中断响应✅ 支持✅ 支持
锁绑定必须绑定 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 机制,它提供了:

  1. 更精细的控制:多条件队列支持
  2. 更安全的操作:与 Lock 集成,避免监视器锁的缺陷
  3. 更灵活的使用:支持超时和不可中断等待
  4. 更高效的唤醒:精确唤醒特定条件的线程

正确使用 Condition 的关键点:

  • 始终在 while 循环中检查条件
  • 使用 try-finally 确保锁释放
  • 合理选择 signal 和 signalAll
  • 考虑使用超时机制避免永久阻塞
  • 注意信号丢失和虚假唤醒问题

通过 Condition,开发者可以构建更高效、更可靠的并发程序,特别适合实现生产者-消费者模式、任务协调、资源池管理等复杂并发场景。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值