首页 > 编程语言 >Java并发基础:CountDownLatch全面解析!

Java并发基础:CountDownLatch全面解析!

时间:2024-02-02 15:31:48浏览次数:17  
标签:Java 计数 并发 任务 线程 CountDownLatch 执行 等待

Java并发基础:CountDownLatch全面解析! - 程序员古德

内容概要

CountDownLatch的优点在于能够简洁高效地协调多个线程的执行顺序,确保一组线程都完成后才触发其他线程的执行,适用于资源加载、任务初始化等场景。它提供了清晰的等待/通知机制,易于理解和使用,是提升多线程程序性能和可靠性的重要工具。

核心概念

CountDownLatchjava.util.concurrent 中的一个类,主要用来解决多线程之间的协同工作问题,特别是当一个或多个线程需要等待其他线程完成一系列操作后才能继续执行的情况。

CountDownLatch允许一个或多个线程等待其他一组线程完成操作,它使用一个计数器来初始化需要等待的线程数量,每当一个线程完成了它的任务,计数器就会递减,当计数器归零时,意味着所有需要等待的线程都已经完成了它们的任务,此时等待的线程(通常是一个或多个主线程)就可以继续执行了。

使用CountDownLatch可以更精确地控制线程的执行顺序和时机,例如,在一个多阶段的任务中,可能希望所有的数据预处理线程都完成后,再启动一个线程来进行数据汇总,使用CountDownLatch 可以很容易地实现这种需求。

代码案例

下面是一个简单的代码示例,演示了如何使用CountDownLatch,如下代码:

import java.util.concurrent.CountDownLatch;  
  
public class CountDownLatchExample {  
  
    // 定义一个包含3个计数的CountDownLatch  
    private static final int WORKER_THREADS = 3;  
    private static final CountDownLatch latch = new CountDownLatch(WORKER_THREADS);  
  
    public static void main(String[] args) throws InterruptedException {  
        // 创建并启动工作线程  
        for (int i = 0; i < WORKER_THREADS; i++) {  
            new Thread(() -> {  
                System.out.println("工作线程" + Thread.currentThread().getId() + "正在执行任务...");  
                try {  
                    // 模拟任务执行时间  
                    Thread.sleep((long) (Math.random() * 1000));  
                } catch (InterruptedException e) {  
                    e.printStackTrace();  
                }  
                System.out.println("工作线程" + Thread.currentThread().getId() + "任务执行完毕!");  
                // 当前工作线程完成任务后,CountDownLatch计数减1  
                latch.countDown();  
            }).start();  
        }  
  
        // 主线程在此等待,直到所有工作线程都完成任务  
        latch.await();  
        System.out.println("所有工作线程都已完成任务,主线程继续执行...");  
    }  
}

在这段代码中,定义了一个CountDownLatch实例latch,并初始化其计数为工作线程的数量(在这个例子中是3),在main方法中,创建了3个工作线程,并启动它们,每个工作线程都执行一个任务,任务完成后调用latch.countDown()方法将CountDownLatch的计数减1,主线程调用latch.await()方法等待,直到CountDownLatch的计数减为0(即所有工作线程都完成了任务)才会继续执行,当所有工作线程都完成任务后,主线程会打印出一条消息表示它可以继续执行了。

如下代码执行结果:

工作线程11正在执行任务...  
工作线程12正在执行任务...  
工作线程13正在执行任务...  
工作线程12任务执行完毕!  
工作线程11任务执行完毕!  
工作线程13任务执行完毕!  
所有工作线程都已完成任务,主线程继续执行...

核心API

CountDownLatch 类主要提供了以下几个核心方法:

  1. CountDownLatch(int count),构造函数,用来初始化一个倒计时计数器,设置初始计数值,参数 count 表示需要等待的事件数量。
  2. void await(),使当前线程在锁存器倒计数至零之前一直等待,除非线程被中断或发生了其他不可预料的事情,如果当前计数为零,则此方法立即返回,如果当前计数大于零,则为了使线程能够继续执行,当前线程必须禁用中断,并且锁存器计数必须减至零,或者此线程必须被其他线程中断。
  3. boolean await(long timeout, TimeUnit unit),使当前线程在锁存器倒计数至零之前一直等待,除非线程被中断、超出了指定的等待时间,或者发生了其他不可预料的事情,如果当前计数为零,则此方法立即返回 true 值,如果当前计数大于零,则此方法将一直阻塞,直到以下三种情况之一发生:
    1. 锁存器计数减至零;此时方法返回 true
    2. 其他线程中断了当前线程;此时方法抛出 InterruptedException
    3. 已超出了指定的等待时间;此时方法返回 false
  4. void countDown(),递减锁存器的计数,如果计数到达零,则释放所有等待的线程,如果当前计数大于零,则将计数减少,如果新的计数为零,出于线程调度的目的,将释放所有等待的线程。
  5. long getCount(),返回当前计数,此方法通常用于调试和测试,而不是用于同步控制,因为它可能与其他操作竞态。

其中await()countDown() 是最常用的,await() 方法用于阻塞当前线程,直到计数器减至零;countDown() 方法用于将计数器减一,这两个方法通常在不同的线程中调用,以实现线程间的协调。

核心总结

Java并发基础:CountDownLatch全面解析!- 程序员古德

CountDownLatch是Java并发编程中的一把利器,它简洁易用,能有效协调多个线程的执行顺序,优点在于,它能确保一组线程都完成后,再触发其他线程的执行,这在很多场景下都非常有用,比如资源加载、任务初始化等,但同时,它也有一些局限性,比如无法重置计数,一旦计数到零,就不能再次使用了。而且,它只能等待固定数量的线程,不够灵活。

关注我,每天学习互联网编程技术 - 程序员古德

END!

标签:Java,计数,并发,任务,线程,CountDownLatch,执行,等待
From: https://blog.51cto.com/bytegood/9555737

相关文章

  • JAVA一维数组介绍和初始化
    一维数组概述一维数组的初始化(声明数组并开辟内存空间)动态初始化1动态初始化2静态初始化一维数组的使用细节......
  • Java将密码加盐加密存储和校验
    注册和登陆的时候,需要加密和校验,以下为加密和解密代码packageorg.ongoal.common.config;importorg.springframework.util.DigestUtils;importorg.springframework.util.StringUtils;importjava.util.UUID;publicclassPasswordUtil{/***加盐算法->格......
  • java开发中业务层和数据层的区别
    其实标准业务层开发很多初学者认为就是调用数据层,怎么说呢?这个理解是没有大问题的,更精准的说法应该是组织业务逻辑功能,并根据业务需求,对数据持久层发起调用。有什么差别呢?目标是为了组织出符合需求的业务逻辑功能,至于调不调用数据层还真不好说,有需求就调用,没有需求就不调用。一个......
  • Java设计模式_1(10/23)
    Java设计模式_1(10/23)目录Java设计模式_1(10/23)单例模式定义饿汉式懒汉式懒汉式(双重检查锁)简单工厂模式定义代码优点缺点工厂模式定义抽象工厂模式装饰器模式适配器模式观察者模式定义外观模式定义状态模式定义策略模式定义代理模式单例模式定义确保类只有一个实例,而且自行......
  • Java 中的List
    ListList接口常用方法List集合存储元素特点:有序可重复List既然是Collection接口的子接口,那么肯定List接口有自己的“特色”方法以下列出List特有的常用的方法:voidadd(intindex,Eelement)将指定的元素插入此列表中的指定位置(可选操作)。Objectget(intindex)返回......
  • java: Compilation failed: internal java compiler error
    idea启动项目后出现 java:Compilationfailed:internaljavacompilererror错误第一种情况:idea的JDK版本和项目配置的不同。解决方法:查看项目中配置的jdk版本,再查看 idea配置的版本项目配置的:在idea中要查看三个地方的配置 1、File---->Setting------>javacompile......
  • 深入浅出Java多线程(六):Java内存模型
    引言大家好,我是你们的老伙计秀才!今天带来的是[深入浅出Java多线程]系列的第六篇内容:Java内存模型。大家觉得有用请点赞,喜欢请关注!秀才在此谢过大家了!!!在并发编程中,有两个关键问题至关重要,它们是线程间通信机制和线程间同步控制。线程间通信机制线程间通信是指在一个多线程程序......
  • 深入浅出Java多线程(八):volatile
    引言大家好,我是你们的老伙计秀才!今天带来的是[深入浅出Java多线程]系列的第八篇内容:volatile。大家觉得有用请点赞,喜欢请关注!秀才在此谢过大家了!!!在当今的软件开发领域,多线程编程已经成为提高系统性能和响应速度的重要手段。Java作为广泛应用的多线程支持语言,其内存模型(JMM)设计巧妙......
  • java基础面试
    java基础个人介绍:面试官您好,我叫赵英波,本科毕业于黄河科技学院软件工程专业,来自河南省郑州市,从网上看到公司招聘感觉比较适合字迹。所以来争取下这份工作。熟悉javaee,javase,熟悉javaweb,springssm框架。熟悉mysql,redis熟悉消息队列mq,熟悉linux基本命令,了解若依框架......
  • [学习笔记] JavaScript中字符串的Slice()方法
    slice方法是对字符串进行切割/截取的一种方法。string.slice(index1,index2)其中:string为字符串名;index1为数字,意为字符串从第X个字符开始截取,如为1,则从字符串第1个字符开始截取。同时该数可为负数,当设为负数时则是从倒数第X个字符开始截取(但仍旧是向最后一个字符的方......