使用CountDownLatch等待多线程全部执行完成

本文介绍 CountDownLatch 的原理及使用方法,通过示例演示如何利用它实现多线程间的同步,提高处理大量重复任务的效率。

前言
CountDownLatch 允许一个或多个线程等待其他线程完成操作。
应用场景
假如有一个列表的大量数据等待处理,最后全部处理完毕后返回处理结果。普通做法就是从头遍历,一个个顺序执行,这样单线程处理效率不高,我们希望使用多线程的方式处理,同时在主线程等待所有子线程处理完成。

CountDownLatch的构造函数接收一个int类型的参数作为计数器,如果你想等待N个点完成,这里就传入N。
当我们调用一次CountDownLatch的countDown方法时,N就会减1,CountDownLatch的await会阻塞当前线程,直到N变成零。由于countDown方法可以用在任何地方,所以这里说的N个点,可以是N个线程,也可以是1个线程里的N个执行步骤。用在多个线程时,你只需要把这个CountDownLatch的引用传递到线程里。

示例代码

public static void main(String args[]){
        //初始化计数
        AtomicInteger count = new AtomicInteger(0);
        //创建10个线程
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        //设置CountDownLatch为10
        CountDownLatch countDownLatch = new CountDownLatch(10);
        for(int i=0;i<10;i++){
            executorService.execute(() -> {
                //每个线程累加10000次
                for(int j=0;j<10000;j++){
                    count.addAndGet(1);
                }
                //线程最后执行countDown
                countDownLatch.countDown();
            });
        }
        try{
            //调用await方法等待
            countDownLatch.await();
        }catch(Exception e){
            e.printStackTrace();
        }
        System.out.println(count.toString());
    }

最后的执行结果就是10*10000=100000,可见所有线程都处理完了。

扩展
CountDownLatch的await方法还支持超时时间的设置,当等待超时时间子线程还没执行完将不再等待继续执行主线程。

public boolean await(long timeout, TimeUnit unit)

熟练使用多线程处理,可以再处理大量重复性工作时发挥多线程处理的效率优势。

<think>嗯,用户想了解如何使用CountDownLatch执行多线程,而且提供了四个相关的站内引用。用户的问题集中在具体使用方法上,结合引用内容来看,我需要清晰地解释CountDownLatch的机制和实现步骤。 根据引用[2]和引用[3],CountDownLatch的核心是通过计数器控制线程阻塞和释放。初始化时设定线程数,每个线程完成时调用countDown()减1,主线程await()会阻塞直到计数器归零。引用[4]补充说明其底层基于AQS队列同步器实现。 用户可能是个Java开发者,正在处理多线程同步问题。ta特意强调"执行多线程的方法",说明需要可落地的代码示例而非理论阐述。从引用看,ta已理解基础概念,现在需要操作指导。 我会从三个层面展开:1)原理简述(突出计数器机制);2)分步使用指南(结合引用中的初始化、countDownawait要点);3)完整代码示例(模拟主线程等待工作线程的场景)。特别注意引用[3]提到的"计数器无法重置"特性要强调。 用户未提及特定场景,但引用[3]列举了扫描安装包的案例,可以考虑在工作线程模拟中加入文件处理等实操元素。最后补充常见问题,比如异常处理(引用未提及,但实际开发必要)。 </think>下面是使用`CountDownLatch`实现多线程同步的详细步骤和代码示例: --- ### **CountDownLatch 的核心机制** 1. **初始化计数器**:设定需要等待线程数量 `N`(如 `CountDownLatch latch = new CountDownLatch(3)`) 2. **子线程完成任务后减1**:每个线程执行完毕后调用 `latch.countDown()` 3. **主线程阻塞等待**:主线程调用 `latch.await()` 阻塞,直到计数器归零[^2][^3] --- ### **完整代码示例(Java)** ```java import java.util.concurrent.CountDownLatch; public class CountDownLatchDemo { public static void main(String[] args) throws InterruptedException { // 1. 初始化计数器(需等待3个子线程CountDownLatch latch = new CountDownLatch(3); // 2. 创建并启动子线程 for (int i = 1; i <= 3; i++) { new Thread(new Worker(latch), "线程-" + i).start(); } System.out.println("主线程等待线程完成..."); // 3. 主线程阻塞,直到计数器归零 latch.await(); // 4. 所有子线程完成执行 System.out.println("所有子线程完成!主线程继续执行"); } static 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(1000); // 模拟任务耗时 } catch (InterruptedException e) { e.printStackTrace(); } finally { // 任务完成,计数器减1 latch.countDown(); System.out.println(Thread.currentThread().getName() + " 已完成"); } } } } ``` --- ### **执行流程解析** 1. **初始化**:创建计数器 `latch(3)` 2. **子线程工作**: - 每个线程执行任务后调用 `latch.countDown()` - 计数器值从 `3 → 2 → 1 → 0` 3. **主线程恢复**: - 当计数器归零时,`latch.await()` 自动释放阻塞 - 主线程继续后续逻辑[^3][^4] --- ### **关键特性** 1. **一次性**:计数器归零后不可重置(若需重用,改用 `CyclicBarrier`)[^3] 2. **超时机制**:支持带超时的等待 `latch.await(5, TimeUnit.SECONDS)` 3. **应用场景**: - 并行任务汇总(如分布式计算) - 服务启动依赖检查(需多个组件初始化完成) - 批量数据处理(分片任务同步)[^1][^3] --- ### **典型输出** ``` 主线程等待线程完成... 线程-1 正在执行任务 线程-2 正在执行任务 线程-3 正在执行任务 线程-1 已完成 线程-2 已完成 线程-3 已完成 所有子线程完成!主线程继续执行 ``` ---
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值