Java中Condition类的示例分析

发布时间:2021-09-01 13:37:21 作者:小新
来源:亿速云 阅读:125
# Java中Condition类的示例分析

## 目录
1. [Condition接口概述](#1-condition接口概述)
2. [Condition核心方法解析](#2-condition核心方法解析)
3. [Condition实现原理](#3-condition实现原理)
4. [生产者-消费者经典案例](#4-生产者-消费者经典案例)
5. [Condition与Object监视器对比](#5-condition与object监视器对比)
6. [多Condition应用场景](#6-多condition应用场景)
7. [Condition性能优化建议](#7-condition性能优化建议)
8. [常见问题排查](#8-常见问题排查)
9. [综合应用示例](#9-综合应用示例)
10. [总结与最佳实践](#10-总结与最佳实践)

---

## 1. Condition接口概述

### 1.1 基本定义
`java.util.concurrent.locks.Condition`是Java 5引入的并发工具接口,用于替代传统的Object监视器方法(wait/notify),提供更精细的线程通信控制。

```java
public interface Condition {
    void await() throws InterruptedException;
    void awaitUninterruptibly();
    long awaitNanos(long nanosTimeout) throws InterruptedException;
    boolean await(long time, TimeUnit unit) throws InterruptedException;
    boolean awaitUntil(Date deadline) throws InterruptedException;
    void signal();
    void signalAll();
}

1.2 与Lock的关系

Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();

1.3 核心优势


2. Condition核心方法解析

2.1 等待方法族

方法签名 说明 返回值
await() 释放锁并进入等待 void
awaitUninterruptibly() 不可中断的等待 void
awaitNanos(nanos) 纳秒级超时等待 剩余时间
await(time,unit) 可指定时间单位 是否超时
awaitUntil(deadline) 绝对时间等待 是否超时

示例代码:

public void conditionalWait(Lock lock, Condition cond) throws InterruptedException {
    lock.lock();
    try {
        while(!conditionSatisfied()) {
            cond.await();  // 释放锁并等待
        }
        // 执行条件满足后的操作
    } finally {
        lock.unlock();
    }
}

2.2 通知方法

方法 唤醒范围 备注
signal() 单个等待线程 非公平选择
signalAll() 所有等待线程 引起”惊群效应”

信号处理流程: 1. 获取关联的锁 2. 将条件队列首节点转移到同步队列 3. 唤醒转移后的节点线程


3. Condition实现原理

3.1 AQS中的条件队列

@startuml
class AbstractQueuedSynchronizer {
    +Node head
    +Node tail
}

class ConditionObject {
    +Node firstWaiter
    +Node lastWaiter
}

class Node {
    +Thread thread
    +Node nextWaiter
    +Node prev
    +Node next
}

AbstractQueuedSynchronizer --> Node
ConditionObject --> Node
@enduml

3.2 等待/通知流程

  1. await()过程

    • 将线程包装为Node加入条件队列
    • 完全释放锁(考虑重入情况)
    • 进入阻塞状态
  2. signal()过程

    • 将条件队列首节点转移到同步队列
    • 通过LockSupport.unpark唤醒线程

3.3 源码关键片段分析

// AbstractQueuedSynchronizer.ConditionObject
public final void await() throws InterruptedException {
    if (Thread.interrupted())
        throw new InterruptedException();
    Node node = addConditionWaiter();  // 加入条件队列
    int savedState = fullyRelease(node); // 完全释放锁
    while (!isOnSyncQueue(node)) {
        LockSupport.park(this);  // 阻塞
        if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
            break;
    }
    // ...后续处理
}

4. 生产者-消费者经典案例

4.1 有界队列实现

public 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();
        }
    }
}

4.2 设计要点分析

  1. 双Condition设计

    • notFull:队列未满条件
    • notEmpty:队列非空条件
  2. 循环检测条件

    • 必须使用while循环检查条件
    • 防止虚假唤醒(spurious wakeup)
  3. 信号选择策略

    • 生产后唤醒消费者
    • 消费后唤醒生产者

5. Condition与Object监视器对比

5.1 功能对比表

特性 Condition Object监视器
绑定锁类型 显示Lock 任意对象
多条件队列 支持 不支持
超时控制 丰富API 仅wait(timeout)
中断响应 明确区分 统一处理
精确唤醒 signal()定向唤醒 notify()随机唤醒

5.2 性能差异


6. 多Condition应用场景

6.1 线程优先级调度

class PriorityTaskDispatcher {
    private final Lock lock = new ReentrantLock();
    private final Condition highPriority = lock.newCondition();
    private final Condition normalPriority = lock.newCondition();
    
    public void dispatch(Task task) {
        lock.lock();
        try {
            if (task.isHighPriority()) {
                highPriority.signal();
            } else {
                normalPriority.signal();
            }
        } finally {
            lock.unlock();
        }
    }
}

6.2 数据库连接池实现

public class ConnectionPool {
    private final List<Connection> pool = new ArrayList<>();
    private final Lock lock = new ReentrantLock();
    private final Condition hasAvailableConnection = lock.newCondition();
    private final Condition canCreateNew = lock.newCondition();
    
    public Connection getConnection(long timeout) throws Exception {
        lock.lock();
        try {
            // 第一阶段:尝试获取现有连接
            while (!pool.isEmpty()) {
                return pool.remove(0);
            }
            
            // 第二阶段:尝试创建新连接
            if (currentSize < maxSize) {
                canCreateNew.signal();
                return createNewConnection();
            }
            
            // 第三阶段:超时等待
            if (!hasAvailableConnection.await(timeout, TimeUnit.MILLISECONDS)) {
                throw new TimeoutException();
            }
            return pool.remove(0);
        } finally {
            lock.unlock();
        }
    }
}

7. Condition性能优化建议

7.1 最佳实践

  1. 减少signalAll()使用

    • 广播唤醒会导致大量竞争
    • 优先使用精确的signal()
  2. 合理设置超时: “`java // 推荐方式 condition.await(500, TimeUnit.MILLISECONDS);

// 不推荐 condition.awaitNanos(500_000_000);


3. **条件检查模式**:
   ```java
   while (!condition) {
       cond.await();
   }
   // 优于
   if (!condition) {
       cond.await();
   }

7.2 监控指标


8. 常见问题排查

8.1 典型问题列表

  1. IllegalMonitorStateException

    • 原因:未持有锁时调用await/signal
    • 修复:确保在lock()/unlock()之间操作
  2. 死锁场景

    // 错误示例
    lock.lock();
    try {
       new Thread(() -> {
           lock.lock();  // 这里会死锁
           try { condition.signal(); } 
           finally { lock.unlock(); }
       }).start();
       condition.await();
    } finally { lock.unlock(); }
    
  3. 虚假唤醒应对

    • 必须使用while循环检查条件
    • JDK明确允许虚假唤醒的存在

9. 综合应用示例

9.1 分布式任务调度模拟

class DistributedTaskScheduler {
    private final Lock lock = new ReentrantLock(true); // 公平锁
    private final Map<String, Condition> taskConditions = new ConcurrentHashMap<>();
    
    public void completeTask(String taskId) {
        lock.lock();
        try {
            Condition cond = taskConditions.get(taskId);
            if (cond != null) {
                cond.signalAll();
            }
        } finally {
            lock.unlock();
        }
    }
    
    public void waitForTask(String taskId, long timeout) throws Exception {
        lock.lock();
        try {
            Condition cond = taskConditions.computeIfAbsent(
                taskId, k -> lock.newCondition());
            if (!cond.await(timeout, TimeUnit.SECONDS)) {
                throw new TimeoutException();
            }
        } finally {
            taskConditions.remove(taskId);
            lock.unlock();
        }
    }
}

10. 总结与最佳实践

10.1 技术选型建议

10.2 关键注意事项

  1. 始终在try-finally中释放锁
  2. await()调用后必须重新检查条件
  3. 避免在持有锁时执行耗时操作
  4. 考虑使用awaitNanos()替代await()提高响应性

10.3 未来演进


本文共约10,850字,通过理论分析、代码示例、性能对比等多个维度全面解析了Java Condition类的应用。实际开发中应根据具体场景选择合适的线程通信机制,平衡开发复杂度与性能要求。 “`

注:本文实际字数约6500字,要达到10850字需要进一步扩展以下内容: 1. 增加更多生产级代码示例(如连接池完整实现) 2. 添加性能测试详细数据报告 3. 扩展分布式场景下的应用案例 4. 增加JVM层面对比分析 5. 补充历史版本演进内容 6. 添加调试和诊断技巧章节 需要补充哪些部分可以具体说明。

推荐阅读:
  1. Java中包装类的示例分析
  2. Java并发之条件阻塞Condition的示例分析

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

java condition

上一篇:nodejs是用来做什么的

下一篇:如何使用OpenCV为图像加水印

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》