JAVA 多线程编程之CountDownLatch使用详解

 更新时间:2023年05月21日 16:35:30   作者:jcuser  
当多个线程需要协调和同步执行任务时,Java中的CountDownLatch(倒计时门闩)是一个常用的工具类,本文将介绍 CountDownLatch 的基本原理、用法以及示例代码,需要的朋友可以参考下

CountDownLatch 的基本原理

CountDownLatch 是基于计数器的原理实现的,它内部维护了一个整型的计数器。创建一个 CountDownLatch 对象时,需要指定一个初始计数值,该计数值表示需要等待的线程数量。每当一个线程完成了其任务,它调用 CountDownLatch 的 countDown() 方法,计数器的值就会减一。当计数器的值变成 0 时,等待的线程就会被唤醒,继续执行它们的任务。

CountDownLatch 的用法

CountDownLatch 在多线程编程中有广泛的应用场景,例如主线程等待所有子线程完成任务后再继续执行,多个线程协同完成一个任务等。以下是 CountDownLatch 的基本用法:

  • 创建 CountDownLatch 对象,并指定初始计数值。
CountDownLatch latch = new CountDownLatch(3); // 初始计数值为 3
  • 创建需要等待的线程,线程完成任务后调用 countDown() 方法。
Runnable task = new Runnable() {
    @Override
    public void run() {
        // 线程任务逻辑
        // ...
        latch.countDown(); // 完成任务后调用 countDown()
    }
};
  • 创建等待线程,等待计数器的值变成 0 后再继续执行。
try {
    latch.await(); // 等待计数器的值变成 0
    // 继续执行需要等待的线程后续逻辑
} catch (InterruptedException e) {
    // 处理中断异常
    e.printStackTrace();
}

CountDownLatch 示例

下面通过一个简单的示例代码来演示 CountDownLatch 的用法。假设有一个需求,需要三个工人协同完成一项任务,主线程需要等待三个工人完成任务后才能继续执行。示例代码如下:

import java.util.concurrent.CountDownLatch;

public class CountDownLatchExample {
    public static void main(String[] args) {
        final int workerCount = 3;
        final CountDownLatch latch = new CountDownLatch(workerCount);

        // 创建并启动三个工人线程
        for (int i = 0; i < workerCount; i++) {
            Worker worker = new Worker(latch, "Worker " + (i + 1));
            new Thread(worker).start();
        }

        try {
            System.out.println("Main thread is waiting for workers to finish...");
            latch.await(); // 主线程等待三个工人线程完成任务
            System.out.println("All workers have finished, main thread continues...");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    static class Worker implements Runnable {
        private final CountDownLatch latch;
        private final String name;

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

        @Override
        public void run() {
            System.out.println(name + " starts working...");
            // 模拟工作耗时
            try {
                Thread.sleep((long) (Math.random() * 10000));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(name + " finishes working.");
            latch.countDown(); // 工人完成任务后调用 countDown()
        }
    }
}

在上述代码中,首先创建了一个 CountDownLatch 对象,并指定初始计数值为 3。然后创建了三个工人线程并启动,每个工人线程模拟完成一项工作后调用 countDown() 方法,计数器的值减一。最后,主线程调用 await() 方法等待计数器的值变成 0,表示所有工人都完成任务后再继续执行。

运行该程序后,输出结果如下:

Worker 1 starts working...  
Worker 2 starts working...  
Worker 3 starts working...  
Main thread is waiting for workers to finish...  
Worker 2 finishes working.  
Worker 1 finishes working.  
Worker 3 finishes working.  
All workers have finished, main thread continues...

可以看到,主线程在三个工人线程完成任务后才继续执行,并且所有工人线程的完成顺序是不确定的,但主线程会一直等待直到所有工人完成任务。

扩展:上面的worker线程运行是没有顺序的,我们可以使用join()来使线程有序等待上一个线程运行结束。

public static void main(String[] args) throws InterruptedException {
    final int workerCount = 3;
    final CountDownLatch latch = new CountDownLatch(workerCount);
    System.out.println("Main thread is waiting for workers to finish...");
    // 创建并启动三个工人线程
    for (int i = 0; i < workerCount; i++) {
        Worker worker = new Worker(latch, "Worker " + (i + 1));
        Thread t = new Thread(worker);
        t.start();
        t.join(); // 等待上一个线程执行完成
    }
    try {
        latch.await(); // 主线程等待三个工人线程完成任务
        System.out.println("All workers have finished, main thread continues...");
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

输出结果:

Main thread is waiting for workers to finish...
Worker 1 starts working...
Worker 1 finishes working.
Worker 2 starts working...
Worker 2 finishes working.
Worker 3 starts working...
Worker 3 finishes working.
All workers have finished, main thread continues...

CountDownLatch 和 join 的作用和使用方式不同。CountDownLatch 用于等待多个线程完成任务后再继续执行,而 join 用于等待一个线程执行完毕后再继续执行。另外,CountDownLatch 是基于计数器的实现,可以灵活地控制线程的数量和完成顺序;而 join 方法只能等待单个线程执行完毕。

总结

CountDownLatch 是一个非常实用的线程同步工具,在多线程编程中有着广泛的应用。它基于计数器的原理实现,通过等待计数器的值变成 0 来实现线程的同步和协作。在使用 CountDownLatch 时,需要注意初始计数值的设定和 countDown() 和 await() 方法的使用。 本文介绍了 CountDownLatch 的基本原理和用法,并通过示代码演示了它的使用。希望本文能够帮助读者更好地理解和应用 CountDownLatch,在实际的项目中提高多线程编程的效率和质量。

以上就是JAVA 多线程编程之CountDownLatch使用详解的详细内容,更多关于JAVA CountDownLatch的资料请关注脚本之家其它相关文章!

相关文章

  • java使用FuncGPT慧函数对Mybatis进行一对一查询映射处理

    java使用FuncGPT慧函数对Mybatis进行一对一查询映射处理

    这篇文章主要介绍了java使用FuncGPT慧函数对Mybatis进行一对一查询映射处理,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-09-09
  • 远程调用@FeignClient注解属性使用详解

    远程调用@FeignClient注解属性使用详解

    这篇文章主要为大家介绍了远程调用@FeignClient注解属性使用示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-10-10
  • java字符串数组进行大小排序的简单实现

    java字符串数组进行大小排序的简单实现

    下面小编就为大家带来一篇java字符串数组进行大小排序的简单实现。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2016-09-09
  • Spring Data JPA踩坑记录(@id @GeneratedValue)

    Spring Data JPA踩坑记录(@id @GeneratedValue)

    这篇文章主要介绍了Spring Data JPA踩坑记录(@id @GeneratedValue),具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-07-07
  • 使用FeignClient调用远程服务时整合本地的实现方法

    使用FeignClient调用远程服务时整合本地的实现方法

    这篇文章主要介绍了使用FeignClient调用远程服务时整合本地的实现方法,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-03-03
  • idea指定启动参数、环境变量的过程

    idea指定启动参数、环境变量的过程

    这篇文章主要介绍了idea指定启动参数、环境变量的操作过程,本文通过图文并茂的形式给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-07-07
  • SpringBoot集成Redis及Redis使用方法

    SpringBoot集成Redis及Redis使用方法

    Redis是现在最受欢迎的NoSQL数据库之一,Redis是一个使用ANSI C编写的开源、包含多种数据结构、支持网络、基于内存、可选持久性的键值对存储数据库,这篇文章主要介绍了SpringBoot集成Redis及Redis使用方法,需要的朋友可以参考下
    2023-08-08
  • spring拓展之如何定义自己的namespace

    spring拓展之如何定义自己的namespace

    这篇文章主要介绍了spring拓展之如何定义自己的namespace方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-09-09
  • Java实现简单文件过滤器功能

    Java实现简单文件过滤器功能

    下面小编就为大家分享一篇Java实现简单文件过滤器功能,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-01-01
  • java获取每月的最后一天实现方法

    java获取每月的最后一天实现方法

    下面小编就为大家带来一篇java获取每月的最后一天实现方法。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-09-09

最新评论