深入剖析Java Condition机制:原理、实现、规范与实战案例全解

一、Condition机制的核心原理

  1. 1. 定位与优势
    Condition是Java 1.5引入的显式锁(Lock)配套机制,用于替代传统的Object.wait()/notify(),提供更精细的线程控制能力:

    • • 多条件队列:一个Lock可关联多个Condition(如生产者消费者模型中的"非满"、"非空"条件)

    • • 灵活唤醒:支持signal()(唤醒单个)和signalAll()(唤醒全部)

    • • 增强控制:提供超时等待(awaitNanos())、不可中断等待(awaitUninterruptibly())等扩展

  2. 2. 底层实现机制
    Condition基于AQS(AbstractQueuedSynchronizer)实现:

    • • 条件队列:每个Condition维护独立的FIFO等待队列(与AQS同步队列分离)

    • • await()流程
    • • signal()流程:将条件队列的头节点转移到AQS同步队列参与锁竞争


二、核心方法与使用规范

▶ 关键方法

方法

作用

注意点

await()

释放锁并阻塞

需在lock.lock()lock.unlock()之间调用

signal()

唤醒单个等待线程

优先选择最长等待者

signalAll()

唤醒所有等待线程

避免信号丢失但可能引发竞争

▶ 强制规范(违反将报错)
  1. 1. 锁持有要求
    调用await()/signal()/signalAll()必须持有关联的Lock锁,否则抛出IllegalMonitorStateException
    lock.lock();  // 必须先获取锁
    try {
        condition.await(); 
    } finally {
        lock.unlock();
    }
  2. 2. 条件检查范式
    必须使用while循环而非if检查条件,防止 虚假唤醒(Spurious Wakeup)
    while (条件不满足) {  // 必须用while循环!
        condition.await();
    }

    原因:底层操作系统可能导致线程无故唤醒

  3. 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监视器)

多个(可自定义)

超时控制

有限支持

支持awaitNanos()

中断响应

仅抛异常

支持不可中断模式

唤醒精度

只能全部唤醒(notifyAll()

可精准唤醒指定条件队列


五、工程实践建议

  1. 1. 优先使用signal()
    在明确唤醒目标时使用signal()减少竞争,不确定时用signalAll()

  2. 2. 避免嵌套调用
    禁止在Condition等待中嵌套调用其他锁操作,防止死锁

  3. 3. 性能敏感场景选Condition
    高并发队列(如ArrayBlockingQueue)底层采用Condition实现

  4. 4. 监控工具支持
    使用jstack或JProfiler可查看Condition等待队列状态

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值