Java并发编程:CountDownLatch核心原理与实战应用

一、CountdownLatch是什么

CountdownLatch(闭锁/倒计时锁),是Java中用于多线程协作的工具类,核心功能是让一个或多个线程等待其他线程完成操作。

  • 初始化计数器:new CountDownLatch(int count)进行初始化,count参代表需要等待完成任务的数量。
  • 线程阻塞:当一个线程调用await()方法时,如果计数器的值不为 0,该线程会被阻塞,进入等待状态,直到计数器变为 0 或者线程被中断。
  • 计数器递减:其他线程在完成自己的任务后,可以调用**countDown()**方法,该方法会将计数器的值减 1。这个操作是线程安全的,多个线程同时调用countDown()也能正确处理。
  • 唤醒机制:当计数器的值通过countDown()方法递减到 0 时,所有因调用**await()**方法而被阻塞的线程会被唤醒,继续执行后续的代码逻辑。

二:快速上手:代码示例:

public class CountDownLatchTest {

            public static void main(String[] args) throws InterruptedException {
                // 创建CountDownLatch,设置计数器初始值为3
                CountDownLatch latch = new CountDownLatch(3);

                // 创建并启动3个子线程
            for (int i = 0; i < 3; i++) {
                new Thread(new Worker(latch)).start();
            }

            try {
                System.out.println("主线程等待子线程完成...");
                // 主线程调用await()方法,进入阻塞状态
                latch.await();
                System.out.println("所有子线程已完成,主线程继续执行");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    class Worker implements Runnable {
        private final CountDownLatch latch;

        public Worker(CountDownLatch latch) {
            this.latch = latch;
        }

        @Override
        public void run() {
            try {
                System.out.println(Thread.currentThread().getName() + " 开始工作");
                // 模拟子线程工作
                Thread.sleep((long) (Math.random() * 2000));
                System.out.println(Thread.currentThread().getName() + " 工作完成");
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                // 子线程工作完成,调用countDown()方法
                latch.countDown();
            }
        }
    }

控制台输出:
在这里插入图片描述

三、CountDownLatch的使用场景

CountDownLatch典型用法:

场景 说明 生活类比
多任务结果汇总 主线程等待所有子任务完成后汇总数据 组装电脑:等CPU、内存、硬盘安装完成再开机
模拟高并发测试 同时释放N个线程模拟用户并发请求 赛跑:所有选手等待发令枪统一出发
服务依赖启动检查 确保所有依赖服务就绪后主服务启动 火箭发射:检查燃料、导航、通信系统后点火
批量任务进度控制 游戏加载:等待地图、角色、音效资源加载完毕 电影开场:所有观众到齐后放映

场景说明生活类比
多任务结果汇总主线程等待所有子任务完成后汇总数据组装电脑:等CPU、内存、硬盘安装完成再开机
模拟高并发测试同时释放N个线程模拟用户并发请求赛跑:所有选手等待发令枪统一出发
服务依赖启动检查确保所有依赖服务就绪后主服务启动火箭发射:检查燃料、导航、通信系统后点火
批量任务进度控制游戏加载:等待地图、角色、音效资源加载完毕电影开场:所有观众到齐后放映

四、CountDownLatch的不足

CountDownLatch是一次性的,计数器的值只能在构造方法中初始化一次,之后没有任何机制再次对其设置值,当CountDownLatch使用完毕后,它不能再次被使用。

使用注意事项
1.计数器的合理设置:在使用CountDownLatch时,计数器的初始值应根据实际任务需求合理设置。
2.countDown的位置:应尽量放在finally块中,以确保无论任务执行过程中是否发生异常,计数器都会被正确递减。若
3.在调用await()方法时,建议使用带超时参数的**await(long timeout, TimeUnit unit)**方法,以防止线程因某些异常情况导致永久阻塞。

五、底层原理:AQS熟悉爱你

CountDownLatch 的底层是基于 AbstractQueuedSynchronizer(AQS)实现的,AQS 是 Java 并发包中实现同步器的基础框架,它提供了一种高效的方式来管理同步状态和线程等待队列。
1. 关键组件
AQS 同步队列:这是一个双向链表,用于管理阻塞的线程。当一个线程调用await()方法且计数器不为 0 时,该线程会被封装成一个Node节点加入到同步队列中。每个Node包含了线程的引用、等待状态以及前驱和后继节点的引用。
volatile state:AQS 中的state变量是一个volatile修饰的整数,用于记录当前计数器的值。volatile关键字保证了多线程环境下对state的读写操作具有可见性,即一个线程对state的修改能立即被其他线程看到。
CAS 原子操作:在更新state时,使用了 CAS(Compare and Swap)原子操作。CAS 操作包含三个操作数:内存地址、预期原值和新值。只有当内存地址中的实际值与预期原值相等时,才会将新值赋给内存地址,否则操作失败。这种原子操作保证了在多线程环境下对state的更新是线程安全的,避免了竞态条件。

2. 执行流程解析
await () 方法:当一个线程调用await()方法时,首先会检查state是否为 0。如果state不为 0,说明还有任务未完成,当前线程需要等待。此时,线程会被封装成一个Node节点加入到 AQS 同步队列的尾部,并将线程挂起。线程会进入一个自旋等待的过程,不断检查前驱节点是否为头节点且是否能成功获取共享资源(即state是否为 0)。如果条件满足,线程被唤醒并继续执行。
countDown () 方法:当一个线程调用countDown()方法时,会通过 CAS 操作将state减 1。如果减 1 后state的值变为 0,说明所有任务都已完成,此时会唤醒 AQS 同步队列中的所有等待线程。具体过程是从队列头部开始,依次唤醒每个等待的线程,让它们有机会重新竞争资源并继续执行。

内存泄漏风险
当使用CountDownLatch与ExecutorService结合时,要注意及时释放ExecutorService资源。如果ExecutorService未正确关闭,其中的线程可能会一直持有对CountDownLatch的引用,导致CountDownLatch无法被垃圾回收,从而产生内存泄漏。在任务完成后,应及时调用ExecutorService的shutdown()或shutdownNow()方法关闭线程池,释放资源。

中断响应
在等待过程中,若线程被中断,应优先处理InterruptedException异常。CountDownLatch的await()方法会抛出InterruptedException,当捕获到该异常时,应根据业务逻辑进行适当处理,如记录日志、中断其他相关线程或进行资源清理等。避免在捕获异常后简单地忽略或继续执行,导致程序出现不一致的状态或其他潜在问题。

六、常见面试题

与CyclicBarrier区别?

  • CountDownLatch:一次性使用,主线程等待子线程。
  • CyclicBarrier:可重复使用,子线程相互等待。

state变量为什么用volatile修饰?

  • 保证多线程间可见性,确保计数变化实时生效。

CAS操作有什么作用?

  • 原子性更新计数器,避免多线程竞争导致计数错误。

七、总结

  • 核心价值:简化多线程协作,实现"等待-唤醒"控制。
  • 适用场景:任务协调、并发测试、服务依赖管理。
  • 使用口诀:初始化计数 → 任务完成减1 → 归零唤醒主线程。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值