Java中CountdownLatch的用法与底层原理详解

createh51个月前 (03-17)技术教程6

引言

在Java并发编程中,CountdownLatch 是一个非常实用的同步工具类,它允许一个或多个线程等待其他线程完成一组操作后再继续执行。这种机制在需要等待多个线程完成任务时非常有用,比如初始化数据、加载资源文件等场景。

本文将从CountdownLatch的用法和底层原理两个方面进行详细介绍。

CountdownLatch的用法

基本概念

CountdownLatch 初始化时设置一个计数器,该计数器表示需要等待的线程数量。每当有一个线程完成了任务,就将计数器减1。当计数器减至0时,那些因为调用await()方法而等待的线程就会被唤醒,继续执行后面的代码。

主要方法

  • CountdownLatch(int count):构造函数,初始化计数器的值。
  • void countDown():将计数器的值减1。如果计数器的值变为0,则所有等待的线程都会被唤醒。
  • void await():使当前线程在锁存器倒计数至零之前一直等待,除非线程被中断。
  • boolean await(long timeout, TimeUnit unit):使当前线程在锁存器倒计数至零之前一直等待,或者超出了指定的等待时间,则返回false。如果在等待过程中被中断,则抛出InterruptedException。

使用示例

假设我们有一个场景,需要等待5个线程完成任务后再继续执行。下面是一个简单的使用示例:

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class CountdownLatchDemo {
    public static void main(String[] args) throws InterruptedException {
        int threadCount = 5;
        CountdownLatch latch = new CountdownLatch(threadCount);

        ExecutorService executor = Executors.newFixedThreadPool(threadCount);

        for (int i = 0; i < threadcount i executor.submit -> {
                try {
                    // 模拟任务执行
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
                // 任务完成,计数器减1
                latch.countDown();
                System.out.println("任务执行完成,剩余等待线程数:" + latch.getCount());
            });
        }

        // 等待所有任务完成
        latch.await();
        System.out.println("所有任务执行完成,继续执行后续操作...");

        executor.shutdown();
    }
}

CountdownLatch的底层原理

类继承关系

CountdownLatch 类实现了java.util.concurrent.locks.AbstractQueuedSynchronizer(简称AQS)类的一个子类,它利用AQS提供的共享锁(Shared Lock)机制来实现计数器的同步操作。

AQS简介

AQS 是一个用于构建锁和其他同步类的框架。它提供了一个FIFO(先进先出)队列来管理那些已经被阻塞的线程,并且提供了一个共享的int状态值来表示锁的状态或计数器的值。CountdownLatch 使用AQS的共享锁机制,将计数器的值作为AQS的状态值。

核心实现

  • 状态值(State):在CountdownLatch中,AQS的状态值用于表示需要等待的线程数量(即计数器的值)。
  • countDown() 方法:通过调用AQS的tryReleaseShared(int releases)方法将计数器的值减1。如果减1后的值为0,则表示所有线程都已经完成任务,此时会唤醒那些因调用await()方法而阻塞的线程。
  • await() 方法:调用AQS的acquireSharedInterruptibly(int arg)方法使当前线程进入等待状态。如果计数器的值不为0,则线程会被放入AQS的等待队列中。一旦计数器的值变为0,或者线程在等待过程中被中断,线程就会从等待队列中移除,并继续执行后续代码。

总结

CountdownLatch 是Java并发编程中一个非常实用的同步工具类,它通过计数器的方式实现了线程间的同步等待。其底层通过AQS的共享锁机制来实现计数器的同步操作,具有高效、灵活的特点。

通过本文的介绍,希望读者能够深入理解CountdownLatch的用法和底层原理,并在实际开发中灵活运用。

相关文章

Java集合框架:底层实现与实战指南

一、核心概念与底层原理1. HashMap概念基于哈希表的Map接口实现,允许null键/值,非线程安全,元素无序存储。底层实现(JDK8+)数组+链表+红黑树结构默认初始容量16,负载因子0.75链...

2025年Java集合面试题深度解析:高频考点与底层原理揭秘

作为Java开发者的核心知识模块,集合框架在面试中的考察频率常年位居榜首。本文结合大厂真题与源码解析,从高频考点、底层实现、实战陷阱三个维度,整理出最具代表性的15道Java集合面试题,助你精准掌握面...

一学就会 一做就废的Redis:对象底层实现原理的详解

对象在前面的数个章节里, 我们陆续介绍了 Redis 用到的所有主要数据结构, 比如简单动态字符串(SDS)、双端链表、字典、压缩列表、整数集合, 等等。Redis 并没有直接使用这些数据结构来实现键...

图解面试必问之SpringCloud底层实现原理

引言面试中面试官喜欢问组件的实现原理,尤其是常用技术,我们平时使用了SpringCloud还需要了解它的实现原理,这样不仅起到举一反三的作用,还能帮助轻松应对各种问题及有针对的进行扩展。以下是分享一下...

为什么大厂的面试题问的都是底层原理,前阿里P7架构师是这样说的

面试官:看你第一面的介绍不错,你先自我介绍下吧我:我叫小X,目前在负责...(省略800字)面试官:项目中Spring用的多么?我:还可以,基本上都用到面试官:那你讲讲使用Spring的几个核心技术我...

JUC并发—1.Java集合包底层源码剖析一

大纲1.为什么要对JDK源码剖析2.ArrayList源码一:基本原理以及优缺点3.ArrayList源码二:核心方法的原理4.ArrayList源码三:数组扩容以及元素拷贝5.LinkedList源...