Java并发编程(九):CountDownLatch 的介绍和使用

大家好,我是欧阳方超,微信公众号同名。在这里插入图片描述

1 CountDownLatch简介

CountDownLatch是Java并发包中的一个同步工具类,始于JDK1.5,主要用于线程之间的协作。它允许一个或多个线程等待其他线程完成一系列操作后再继续执行。其工作原理类似于Thread.join()方法,但在使用线程池时,CountDownLatch显的更加灵活。
CountDownLatch的构造函数接收一个整型参数,表示计数器的初始值。调用countDown()方法会使计算器的值减一,调用awart()方法会阻塞调用该方法的线程,直到计数器值减为零为止。

1.1 CountDownLatch的工作原理

  • 创建一个CountDownLatch实例并设置计数值。
  • 启动多个线程,每个线程在完成其任务后调用countDown()方法。
  • 主线程调用await()方法,这样主线程会被阻塞,直到计数器的值减为0,随后继续执行。

1.2 常用方法

  • public void await() throws InterruptedException: 阻塞当前线程,直到计数器为0。
  • public boolean await(long timeout, TimeUnit unit) throws - InterruptedException: 阻塞当前线程,直到计数器为0或超时。
  • public void countDown(): 计数器减1。
  • public long getCount(): 返回当前计数值。

2 使用场景

  1. 等待多个线程完成
    当一个线程需要等待多个其他线程完成任务才能执行时,可以使用CountDownLatch。例如,等待多个压缩文件全部下载完成后再统一执行解压操作。
  2. 并发任务的协调
    需要并发执行多个任务时,也可以使用CountDownKatch。例如,跑步比赛中,所有运行员需要等待裁判发号施令才能开跑。

2.1 等待多个线程完成的场景

这个场景也可以理解为多个任务完成后汇总的场景,假设有这样一个任务,需要下载多个压缩文件,然后再执行后续的文件解压操作。

import java.util.concurrent.CountDownLatch;

public class FileDownExtractExample {
    public static void main(String[] args) {

        int numFiles = 3;
        CountDownLatch countDownLatch = new CountDownLatch(numFiles);
        for (int i = 0; i < numFiles; i++) {
            final  int finalId = i + 1;
            new Thread(() -> {
                try {
                    System.out.println("Downloading file " + finalId);
                    Thread.sleep(Math.round(Math.random() * 1000));
                    System.out.println("File " + finalId + " downloaded");
                    countDownLatch.countDown();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }).start();

        }
        System.out.println("Waiting for all files to be downloaded...");
        try {
            countDownLatch.await();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        System.out.println("All files have been downloaded, proceeding with extraction.");
    }
}

在这示例中,countDownLatch的值被初始化为3,代表3个文件下载的任务;每个文件下载线程在下载任务完成后都会调用countDown()方法,将计数器减一,当计数器的值减为零时,await()方法结束,主线程可运行,开始执行后续的解压操作。

2.2 并发任务的协调

假设这样一个场景,有多个运动员需要等待裁判的枪声后才能开跑,模拟程序如下:

import java.util.concurrent.CountDownLatch;

public class RaceExample {
    public static void main(String[] args) {

        int numathletes = 5;
        CountDownLatch countDownLatch = new CountDownLatch(1);
        for (int i = 0; i < numathletes; i++) {
            final int athleteId = i + 1;
            new Thread(() -> {
                try {
                    System.out.println("Athlete " + athleteId + " is ready");
                    countDownLatch.await();
                    System.out.println("Athlete " + athleteId + " starts running");
                    countDownLatch.countDown();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }).start();

        }
        try {
            //模拟裁判准备时间
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Bang! Race begins!");
        countDownLatch.countDown();
    }
}

上面的示例中,首先创建了一个CountDownLatch,初始值为 1,代表裁判的发令操作;然后创建了 5 个运动员线程,每个运动员线程在启动后调用await()方法等待,此时它们都处于阻塞状态;主线程(模拟裁判)在等待 1 秒后,调用countDown()方法,计数器变为零,所有运动员线程被唤醒并开始执行。执行结果如下:

Athlete 4 is ready
Athlete 3 is ready
Athlete 5 is ready
Athlete 2 is ready
Athlete 1 is ready
Bang! Race begins!
Athlete 4 starts running
Athlete 5 starts running
Athlete 3 starts running
Athlete 1 starts running
Athlete 2 starts running

3 总结

CountDownLatch是Java并发编程中一个非常实用的同步工具,它通过简单的计数机制有效地协调多个线程之间的执行顺序。在多线程环境中,合理使用CountDownLatch可以提高程序的可读性和可靠性,使得开发者能够更轻松地管理并发任务。
我是欧阳方超,把事情做好了自然就有兴趣了,如果你喜欢我的文章,欢迎点赞、转发、评论加关注。我们下次见。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值