JDK 8 CountDownLatch 源码详解(详细注释版)
1. 类定义和基本属性
public class CountDownLatch implements java.io.Serializable {
// 序列化版本号
private static final long serialVersionUID = -6424283961411517113L;
/**
* CountDownLatch的核心同步器
* 继承自AbstractQueuedSynchronizer(AQS)
* 通过AQS的state字段来表示计数器的值
*
* 设计巧妙之处:
* - 利用AQS的共享锁机制实现计数功能
* - state=0表示计数器归零,可以通行
* - state>0表示还有线程需要等待
* - 通过共享模式实现多线程同时唤醒
*/
private final Sync sync;
/**
* 同步器内部类
* 继承自AbstractQueuedSynchronizer
* 实现CountDownLatch的具体同步逻辑
*/
private static final class Sync extends AbstractQueuedSynchronizer {
private static final long serialVersionUID = 4982264981922014374L;
/**
* 构造方法
* 初始化计数器的值
* @param count 初始计数器值
*
* 初始化过程:
* 1. 调用AQS的setState方法设置state字段
* 2. state字段表示还需要等待的线程数量
* 3. count必须为非负数
*/
Sync(int count) {
setState(count);
}
/**
* 获取当前计数器值
* @return 当前计数器值
*
* 获取过程:
* 1. 调用AQS的getState方法获取state字段
* 2. state字段表示还需要等待的线程数量
* 3. 返回当前计数器值
*
* 时间复杂度:O(1)
* 线程安全性:完全线程安全
*/
int getCount() {
return getState();
}
/**
* 尝试获取共享锁
* 这是AQS的模板方法,由子类实现
*
* 获取条件:
* - 当state=0时,表示计数器归零,可以获取锁
* - 当state>0时,表示还有线程需要等待,不能获取锁
*
* 返回值含义:
* - 负数:获取失败
* - 0:获取成功,但后续线程不能获取
* - 正数:获取成功,后续线程也可以获取
*
* @param acquires 获取许可数
* @return 获取结果
*
* 时间复杂度:O(1)
* 线程安全性:完全线程安全
*/
protected int tryAcquireShared(int acquires) {
return (getState() == 0) ? 1 : -1;
}
/**
* 尝试释放共享锁
* 这是AQS的模板方法,由子类实现
*
* 释放过程:
* 1. 减少计数器值
* 2. 如果计数器归零,唤醒所有等待的线程
* 3. 返回释放结果
*
* 返回值含义:
* - true:释放成功,需要唤醒等待线程
* - false:释放失败,不需要唤醒等待线程
*
* @param releases 释放许可数
* @return 释放结果
*
* 时间复杂度:O(1)
* 线程安全性:完全原子性
*/
protected boolean tryReleaseShared(int releases) {
// Decrement count; signal when transition to zero
for (;;) {
int c = getState(); // 获取当前计数器值
if (c == 0) // 如果计数器已经归零
return false; // 返回false,不需要唤醒
int nextc = c-1; // 计算新的计数器值
if (compareAndSetState(c, nextc)) // CAS操作更新计数器
return nextc == 0; // 如果计数器归零,返回true需要唤醒
}
}
}
/**
* 构造方法
* 创建一个指定计数器值的CountDownLatch
* @param count 初始计数器值
*
* 构造过程:
* 1. 验证count参数的有效性
* 2. 创建Sync实例
* 3. 初始化计数器值
*
* 参数说明:
* - count必须为非负数
* - count=0表示门闩立即打开
* - count>0表示需要等待指定数量的线程调用countDown()
*
* @throws IllegalArgumentException 如果count为负数
*/
public CountDownLatch(int count) {
if (count < 0) throw new IllegalArgumentException("count < 0");
this.sync = new Sync(count);
}
2. 核心同步方法(详细注释)
/**
* 等待计数器归零
* 如果计数器尚未归零,当前线程会阻塞直到归零
*
* 等待过程:
* 1. 调用AQS的acquireSharedInterruptibly方法
* 2. 如果计数器为0,立即返回
* 3. 如果计数器大于0,加入等待队列并阻塞
* 4. 被唤醒后重新检查计数器
* 5. 重复步骤2-4直到计数器归零
*
* 中断处理:
* - 如果线程在等待过程中被中断,会抛出InterruptedException
* - 线程可以被优雅地中止
*
* 时间复杂度:O(1) 平均情况,O(∞) 最坏情况(等待时间)
* 线程安全性:完全线程安全
*
* @throws InterruptedException 如果线程被中断
*/
public void await() throws InterruptedException {
sync.acquireSharedInterruptibly(1); // 调用AQS的可中断共享获取方法
}
/**
* 等待计数器归零(带超时)
* 如果计数器尚未归零,当前线程会阻塞直到归零或超时
*
* 超时处理:
* 1. 调用AQS的tryAcquireSharedNanos方法
* 2. 如果计数器为0,立即返回true
* 3. 如果计数器大于0,等待指定时间
* 4. 在等待期间可被中断
* 5. 超时后如果计数器仍大于0,返回false
* 6. 超时前计数器归零,返回true
*
* 时间处理:
* - 将时间单位转换为纳秒
* - 使用高精度计时
* - 支持任意时间单位
*
* 时间复杂度:O(1) 平均情况,O(∞) 最坏情况(等待时间)
* 线程安全性:完全线程安全
*
* @param timeout 等待时间
* @param unit 时间单位
* @return 如果计数器归零返回true,如果超时返回false
* @throws InterruptedException 如果线程被中断
*/
public boolean await(long timeout, TimeUnit unit)
throws InterruptedException {
return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));
}
/**
* 减少计数器值
* 将计数器值减1,如果减到0则唤醒所有等待的线程
*
* 减少过程:
* 1. 调用AQS的releaseShared方法
* 2. 在tryReleaseShared中减少计数器值
* 3. 如果计数器归零,返回true
* 4. AQS根据返回值决定是否唤醒等待线程
* 5. 唤醒所有在等待队列中的线程
*
* 原子性保证:
* - 使用CAS操作确保减少操作的原子性
* - 避免竞态条件
* - 保证计数器的一致性
*
* 时间复杂度:O(1) 平均情况,O(∞) 最坏情况(高竞争)
* 线程安全性:完全原子性
*/
public void countDown() {
sync.releaseShared(1); // 调用AQS的共享释放方法
}
/**
* 获取当前计数器值
* 返回当前还需要等待的线程数量
*
* 查询过程:
* 1. 调用Sync的getCount方法
* 2. 获取AQS的state字段值
* 3. 返回当前计数器值
*
* 注意事项:
* - 这是一个瞬时值,可能很快过时
* - 在高并发环境下可能不是准确值
* - 主要用于调试和监控
*
* 时间复杂度:O(1)
* 线程安全性:完全线程安全
*
* @return 当前计数器值
*/
public long getCount() {
return sync.getCount();
}
/**
* 返回对象的字符串表示
* 重写Object类的toString方法
*
* 字符串格式:
* - 包含类名和当前计数器值
* - 便于调试和日志输出
* - 符合Java标准格式
*
* @return 对象的字符串表示
*/
public String toString() {
return super.toString() + "[Count = " + sync.getCount() + "]";
}
3. CountDownLatch 的特点分析
核心设计理念:
/**
* CountDownLatch的核心设计思想:
*
* 1. AQS集成:
* - 继承AbstractQueuedSynchronizer
* - 复用成熟的队列管理机制
* - 提供完整的同步框架
* - 支持共享模式
*
* 2. 计数器机制:
* - 使用AQS的state字段表示计数器
* - state=0表示门闩打开
* - state>0表示门闩关闭
* - 通过CAS操作保证原子性
*
* 3. 共享锁语义:
* - 使用共享模式实现多线程同时唤醒
* - 多个线程可以同时通过门闩
* - 提高并发性能
*
* 4. 一次性使用:
* - 计数器只能减少,不能增加
* - 一旦归零不能重置
* - 保证语义的清晰性
*
* 5. 线程安全:
* - 所有操作都是线程安全的
* - 支持高并发环境
* - 无死锁风险
*
* 6. 灵活的等待机制:
* - 支持无限期等待
* - 支持可中断等待
* - 支持超时等待
* - 提供多种等待选项
*
* 7. 高效的唤醒机制:
* - 计数器归零时一次性唤醒所有等待线程
* - 避免逐个唤醒的开销
* - 提高唤醒效率
*
* 适用场景:
* - 主线程等待多个子线程完成
* - 实现启动门闩
* - 实现关闭门闩
* - 协调多个线程的执行
* - 实现简单的屏障机制
*/
性能特征分析:
/**
* CountDownLatch的性能特征:
*
* 时间复杂度:
* - countDown(): O(1) 平均,O(∞) 最坏(高竞争)
* - await(): O(1) 如果计数器为0,O(∞) 如果需要等待
* - getCount(): O(1) 直接读取state字段
* - await(timeout): O(1) 平均,O(∞) 最坏(等待时间)
*
* 空间复杂度:
* - O(1) 基本存储空间
* - O(n) 等待队列空间(n为等待线程数)
* - 每个实例固定开销很小
*
* 并发特性:
* - 完全线程安全
* - 支持高并发读写
* - 无锁设计(通过AQS)
* - 共享模式提高性能
*
* 与join()对比:
* - CountDownLatch > Thread.join()(功能更丰富)
* - CountDownLatch > Thread.join()(性能更好)
* - CountDownLatch > Thread.join()(更灵活)
*
* 与wait/notify对比:
* - CountDownLatch > wait/notify(更简单)
* - CountDownLatch > wait/notify(更安全)
* - CountDownLatch > wait/notify(更高效)
*
* 内存使用:
* - 每个实例固定开销很小
* - 等待线程会增加内存使用
* - 及时GC,避免内存泄漏
*
* 适用性:
* - 简单的线程协调:性能优异
* - 复杂的同步逻辑:可能不如其他机制
* - 一次性的同步需求:完美匹配
* - 需要重置的场景:不适合
*
* 性能优化:
* - 合理设置初始计数器值
* - 避免不必要的等待
* - 使用超时机制避免无限等待
* - 正确处理中断异常
* - 监控等待线程数量
*/
4. 使用示例和最佳实践
/**
* 使用示例:
*
* // 基本使用:主线程等待多个子线程完成
* CountDownLatch latch = new CountDownLatch(3);
*
* // 启动三个工作线程
* for (int i = 0; i < 3; i++) {
* final int taskId = i;
* new Thread(() -> {
* try {
* // 执行任务
* System.out.println("Task " + taskId + " started");
* Thread.sleep(1000); // 模拟任务执行
* System.out.println("Task " + taskId + " completed");
* } catch (InterruptedException e) {
* Thread.currentThread().interrupt();
* } finally {
* latch.countDown(); // 任务完成后减少计数器
* }
* }).start();
* }
*
* // 主线程等待所有任务完成
* try {
* System.out.println("Main thread waiting for tasks to complete...");
* latch.await(); // 等待计数器归零
* System.out.println("All tasks completed!");
* } catch (InterruptedException e) {
* Thread.currentThread().interrupt();
* }
*
* // 带超时的等待示例
* CountDownLatch timeoutLatch = new CountDownLatch(1);
*
* Thread worker = new Thread(() -> {
* try {
* // 执行长时间任务
* Thread.sleep(5000);
* timeoutLatch.countDown();
* } catch (InterruptedException e) {
* Thread.currentThread().interrupt();
* }
* });
* worker.start();
*
* try {
* // 等待最多2秒
* if (timeoutLatch.await(2, TimeUnit.SECONDS)) {
* System.out.println("Worker completed within timeout");
* } else {
* System.out.println("Worker timed out");
* worker.interrupt(); // 中断工作线程
* }
* } catch (InterruptedException e) {
* Thread.currentThread().interrupt();
* }
*
* // 启动门闩示例
* CountDownLatch startLatch = new CountDownLatch(1);
*
* // 创建多个工作线程
* for (int i = 0; i < 5; i++) {
* final int workerId = i;
* new Thread(() -> {
* try {
* System.out.println("Worker " + workerId + " ready");
* startLatch.await(); // 等待启动信号
* System.out.println("Worker " + workerId + " started working");
* // 执行实际工作
* } catch (InterruptedException e) {
* Thread.currentThread().interrupt();
* }
* }).start();
* }
*
* // 等待所有准备工作完成
* Thread.sleep(1000);
* System.out.println("Starting all workers...");
* startLatch.countDown(); // 发送启动信号
*
* // 关闭门闩示例
* CountDownLatch shutdownLatch = new CountDownLatch(3);
*
* // 创建服务线程
* for (int i = 0; i < 3; i++) {
* final int serviceId = i;
* new Thread(() -> {
* try {
* System.out.println("Service " + serviceId + " started");
* // 服务运行
* while (!Thread.currentThread().isInterrupted()) {
* Thread.sleep(100);
* // 检查服务状态
* }
* } catch (InterruptedException e) {
* System.out.println("Service " + serviceId + " interrupted");
* } finally {
* shutdownLatch.countDown(); // 服务关闭后减少计数器
* System.out.println("Service " + serviceId + " shut down");
* }
* }).start();
* }
*
* // 关闭所有服务
* public void shutdownServices() {
* System.out.println("Shutting down all services...");
* // 中断所有服务线程
* Thread.currentThread().getThreadGroup().interrupt();
*
* try {
* // 等待所有服务关闭
* if (shutdownLatch.await(10, TimeUnit.SECONDS)) {
* System.out.println("All services shut down successfully");
* } else {
* System.out.println("Some services failed to shut down in time");
* }
* } catch (InterruptedException e) {
* Thread.currentThread().interrupt();
* }
* }
*
* // 多阶段任务协调示例
* class MultiStageTaskCoordinator {
* private final CountDownLatch stage1Latch;
* private final CountDownLatch stage2Latch;
* private final CountDownLatch completionLatch;
*
* public MultiStageTaskCoordinator(int stage1Tasks, int stage2Tasks) {
* this.stage1Latch = new CountDownLatch(stage1Tasks);
* this.stage2Latch = new CountDownLatch(stage2Tasks);
* this.completionLatch = new CountDownLatch(stage1Tasks + stage2Tasks);
* }
*
* public void executeStage1Task() {
* try {
* // 执行第一阶段任务
* System.out.println("Executing stage 1 task");
* Thread.sleep(1000);
* } catch (InterruptedException e) {
* Thread.currentThread().interrupt();
* } finally {
* stage1Latch.countDown();
* completionLatch.countDown();
* }
* }
*
* public void executeStage2Task() {
* try {
* // 等待第一阶段完成
* stage1Latch.await();
* // 执行第二阶段任务
* System.out.println("Executing stage 2 task");
* Thread.sleep(1000);
* } catch (InterruptedException e) {
* Thread.currentThread().interrupt();
* } finally {
* stage2Latch.countDown();
* completionLatch.countDown();
* }
* }
*
* public void waitForCompletion() throws InterruptedException {
* completionLatch.await();
* System.out.println("All tasks completed");
* }
* }
*
* 最佳实践:
*
* 1. 正确使用countDown:
* CountDownLatch latch = new CountDownLatch(3);
*
* // 正确的做法:在finally块中调用countDown
* new Thread(() -> {
* try {
* // 执行任务
* performTask();
* } catch (Exception e) {
* // 处理异常
* System.err.println("Task failed: " + e.getMessage());
* } finally {
* latch.countDown(); // 必须在finally块中调用
* }
* }).start();
*
* // 错误的做法:可能忘记调用countDown
* // new Thread(() -> {
* // performTask(); // 如果抛出异常,countDown不会被调用
* // latch.countDown(); // 可能不会执行到这里
* // }).start();
*
* 2. 合理使用await:
* CountDownLatch latch = new CountDownLatch(1);
*
* // 正确的做法:处理中断异常
* try {
* latch.await();
* System.out.println("Ready to proceed");
* } catch (InterruptedException e) {
* Thread.currentThread().interrupt(); // 恢复中断状态
* System.out.println("Waiting interrupted");
* }
*
* // 带超时的等待
* try {
* if (latch.await(5, TimeUnit.SECONDS)) {
* System.out.println("Operation completed within timeout");
* } else {
* System.out.println("Operation timed out");
* }
* } catch (InterruptedException e) {
* Thread.currentThread().interrupt();
* }
*
* 3. 设置合理的计数器值:
* // 根据实际需要的任务数量设置
* int taskCount = calculateTaskCount();
* CountDownLatch latch = new CountDownLatch(taskCount);
*
* // 错误的做法:硬编码计数器值
* // CountDownLatch latch = new CountDownLatch(10); // 可能与实际任务数不符
*
* 4. 避免计数器溢出:
* // 确保计数器值不会溢出
* public CountDownLatch createLatch(int count) {
* if (count < 0) {
* throw new IllegalArgumentException("Count must be non-negative");
* }
* if (count > Integer.MAX_VALUE / 2) {
* System.out.println("Warning: Large latch count may cause issues");
* }
* return new CountDownLatch(count);
* }
*
* 5. 正确处理异常:
* CountDownLatch latch = new CountDownLatch(5);
*
* for (int i = 0; i < 5; i++) {
* final int taskId = i;
* new Thread(() -> {
* try {
* performTask(taskId);
* } catch (Exception e) {
* System.err.println("Task " + taskId + " failed: " + e.getMessage());
* // 记录日志
* } finally {
* latch.countDown(); // 无论成功失败都要调用
* }
* }).start();
* }
*
* try {
* latch.await();
* System.out.println("All tasks finished (some may have failed)");
* } catch (InterruptedException e) {
* Thread.currentThread().interrupt();
* }
*
* 6. 使用超时机制:
* CountDownLatch latch = new CountDownLatch(1);
*
* // 不要无限期等待
* try {
* if (!latch.await(30, TimeUnit.SECONDS)) {
* System.out.println("Operation timed out after 30 seconds");
* // 处理超时情况
* handleTimeout();
* }
* } catch (InterruptedException e) {
* Thread.currentThread().interrupt();
* }
*
* 7. 监控和调试:
* CountDownLatch latch = new CountDownLatch(10);
*
* // 定期检查计数器状态
* public void monitorProgress() {
* long currentCount = latch.getCount();
* System.out.println("Remaining tasks: " + currentCount);
* if (currentCount == 0) {
* System.out.println("All tasks completed");
* }
* }
*
* // 记录任务完成情况
* public void trackTaskCompletion(int taskId) {
* System.out.println("Task " + taskId + " completed, " +
* latch.getCount() + " tasks remaining");
* latch.countDown();
* }
*
* 8. 避免重复调用countDown:
* CountDownLatch latch = new CountDownLatch(1);
*
* // 错误的做法:可能重复调用
* // if (someCondition) {
* // latch.countDown();
* // }
* // latch.countDown(); // 可能重复调用
*
* // 正确的做法:确保只调用一次
* private final AtomicBoolean countedDown = new AtomicBoolean(false);
*
* public void safeCountDown() {
* if (countedDown.compareAndSet(false, true)) {
* latch.countDown();
* }
* }
*
* 9. 合理使用多个门闩:
* // 启动门闩和完成门闩
* CountDownLatch startLatch = new CountDownLatch(1);
* CountDownLatch finishLatch = new CountDownLatch(5);
*
* // 工作线程
* for (int i = 0; i < 5; i++) {
* final int workerId = i;
* new Thread(() -> {
* try {
* startLatch.await(); // 等待启动信号
* System.out.println("Worker " + workerId + " started");
* performWork();
* } catch (InterruptedException e) {
* Thread.currentThread().interrupt();
* } finally {
* finishLatch.countDown(); // 完成后减少计数器
* }
* }).start();
* }
*
* // 控制线程
* new Thread(() -> {
* try {
* Thread.sleep(1000); // 准备时间
* System.out.println("Starting all workers...");
* startLatch.countDown(); // 发送启动信号
*
* System.out.println("Waiting for all workers to finish...");
* finishLatch.await(); // 等待所有工作完成
* System.out.println("All workers finished");
* } catch (InterruptedException e) {
* Thread.currentThread().interrupt();
* }
* }).start();
*
* 10. 性能调优:
* // 在高并发场景下监控性能
* CountDownLatch latch = new CountDownLatch(1000);
*
* // 监控等待时间
* public void monitorAwaitTime() {
* long startTime = System.nanoTime();
* try {
* latch.await();
* long endTime = System.nanoTime();
* long duration = endTime - startTime;
* System.out.println("Wait time: " + duration + " nanoseconds");
* } catch (InterruptedException e) {
* Thread.currentThread().interrupt();
* }
* }
*
* // 批量操作优化
* public void batchCountDown(CountDownLatch latch, int count) {
* for (int i = 0; i < count; i++) {
* latch.countDown();
* }
* }
*/
5. 与其他同步机制的比较
/**
* CountDownLatch vs CyclicBarrier vs Semaphore vs Phaser:
*
* CountDownLatch:
* - 一次性使用,计数器只能减少
* - 支持一个或多个线程等待
* - 支持多个线程减少计数器
* - 不支持重置
* - 适用于简单的等待/通知场景
*
* CyclicBarrier:
* - 可重复使用,支持重置
* - 所有线程相互等待
* - 到达屏障点后一起继续
* - 支持回调函数
* - 适用于分阶段并行计算
*
* Semaphore:
* - 控制资源访问数量
* - 支持许可证的获取和释放
* - 可以动态调整许可数量
* - 支持公平性和非公平性
* - 适用于资源池管理
*
* Phaser:
* - JDK 7新增,功能最强大
* - 支持动态注册和注销参与者
* - 支持分层组织
* - 可重复使用
* - 适用于复杂的同步场景
*
* 性能对比:
* - 简单等待:CountDownLatch > CyclicBarrier > Semaphore > Phaser
* - 复杂同步:Phaser > CyclicBarrier > Semaphore > CountDownLatch
* - 内存使用:CountDownLatch < CyclicBarrier < Semaphore < Phaser
* - 功能丰富度:Phaser > CyclicBarrier > Semaphore > CountDownLatch
*
* 选择建议:
* - 简单等待多个事件完成:CountDownLatch
* - 分阶段并行计算:CyclicBarrier
* - 资源访问控制:Semaphore
* - 复杂同步需求:Phaser
* - 需要重置功能:CyclicBarrier或Phaser
* - 高性能简单场景:CountDownLatch
*
* 使用场景:
* - CountDownLatch:主线程等待子线程完成、启动门闩、关闭门闩
* - CyclicBarrier:并行计算、分阶段任务协调
* - Semaphore:资源池、流量控制、连接池
* - Phaser:复杂的工作流、动态参与者管理
*/
6. 总结
CountDownLatch 的核心特性:
-
一次性同步:
- 计数器只能减少,不能增加
- 一旦归零不能重置
- 保证语义的清晰性
- 适用于一次性的同步需求
-
共享锁语义:
- 基于AQS的共享模式实现
- 多个线程可以同时通过门闩
- 提高并发性能
- 支持共享锁的所有特性
-
灵活的等待机制:
- 支持无限期等待
- 支持可中断等待
- 支持超时等待
- 提供多种等待选项
- 满足不同的使用需求
-
高效的唤醒机制:
- 计数器归零时一次性唤醒所有等待线程
- 避免逐个唤醒的开销
- 提高唤醒效率
- 减少系统调用次数
-
线程安全:
- 所有操作都是线程安全的
- 支持高并发环境
- 无死锁风险
- 基于AQS的成熟实现
-
丰富的API:
- 提供详细的计数器查询
- 支持监控和诊断
- 便于调试和性能调优
- 符合Java标准规范
适用场景:
- 主线程等待多个子线程完成
- 实现启动门闩
- 实现关闭门闩
- 协调多个线程的执行
- 实现简单的屏障机制
- 需要一次性同步的场景
注意事项:
- 必须确保countDown被正确调用
- 避免计数器永远不会归零的情况
- 合理使用超时机制避免无限等待
- 正确处理中断异常
- 监控等待线程数量
- 避免重复调用countDown
性能优化建议:
- 根据实际需求设置合适的计数器值
- 使用超时机制避免无限等待
- 正确处理中断异常
- 在finally块中调用countDown
- 监控计数器状态
- 避免不必要的等待
- 合理使用多个门闩
- 定期分析和调优性能


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



