• CountDownLatch闭锁原理解析


    CountDownLatch闭锁原理解析

    Java并发编程中,CountDownLatch是一个常用的工具类,用于实现闭锁(latch)。闭锁是一种常见的同步机制,用于控制线程的执行流程,确保某些线程在执行之前满足特定的条件。CountDownLatch尤其在多线程协作场景中非常重要,例如,当一个线程需要等待其他多个线程完成各自的工作后才能执行下一步操作时,CountDownLatch可以发挥巨大作用。

    CountDownLatch实现

    CountDownLatch是一个Java并发库中的类,位于java.util.concurrent包中。它提供了两个主要的方法:await()countDown()await()方法用于阻塞当前线程,直到所有参与方都调用了countDown()方法,否则不会继续执行。countDown()方法则用于减少 latch 的计数,表示一个参与方已经完成自己的任务。当计数减为0时,所有因调用await()而阻塞的线程将恢复执行。

    CountDownLatch的核心是一个内部类CountDownLatch$CountDownLatchlatch,它实现了AbstractQueuedSynchronizer(AQS)。这个内部类通过维护一个计数器(计数为参与方的数量)和一个队列来工作。当一个线程调用await()方法时,它会被放入队列中并阻塞,同时会减少计数器的值。当一个线程调用countDown()方法时,计数器会减少1,如果计数器值为0,那么队列中的所有线程都将被唤醒并从阻塞状态变为非阻塞状态,可以继续执行。

    工作原理分析

    CountDownLatch的工作原理可以简单概括为:在多线程协作中,一些线程在执行完自己的任务之后,会调用countDown()方法来减少计数器的值。当计数器值为0时,所有因调用await()而阻塞的线程将恢复执行。

    这个机制确保了只有当所有参与方都完成任务后,才允许某些线程继续执行。这对于多线程之间的同步和协调非常有用。例如,考虑一个场景,有一个任务需要被多个线程分别处理,并且只有在所有线程都完成后,主线程才继续执行。在这种情况下,我们可以使用CountDownLatch来实现这个需求。

    简单Java代码示例

    以下是一个简单的Java代码示例来说明如何使用CountDownLatch:

    import java.util.concurrent.CountDownLatch;
    import java.util.concurrent.TimeUnit;
    
    public class CountDownLatchExample {
        public static void main(String[] args) throws InterruptedException {
            final CountDownLatch latch = new CountDownLatch(3); // 3参与方
    
            // 创建3个线程分别执行任务并调用countDown()方法
            new Thread(() -> {
                System.out.println("Thread 1 start");
                try {
                    TimeUnit.SECONDS.sleep(2); // 模拟任务执行时间
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("Thread 1 end");
                latch.countDown(); // 完成任务后减少计数器值
            }).start();
    
            new Thread(() -> {
                System.out.println("Thread 2 start");
                try {
                    TimeUnit.SECONDS.sleep(1); // 模拟任务执行时间
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("Thread 2 end");
                latch.countDown(); // 完成任务后减少计数器值
            }).start();
    
            new Thread(() -> {
                System.out.println("Thread 3 start");
                try {
                    TimeUnit.SECONDS.sleep(3); // 模拟任务执行时间
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("Thread 3 end");
                latch.countDown(); // 完成任务后减少计数器值
            }).start();
    
            // 主线程等待所有参与方完成任务后继续执行
            latch.await();
            System.out.println("All tasks completed, main thread continues.");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46

    在上面的代码示例中,我们创建了一个CountDownLatch实例并设定参与方数量为3。然后创建了3个线程来模拟任务执行,每个线程在完成任务后都会调用countDown()方法。主线程则通过await()方法等待所有参与方完成任务。当所有参与方都调用了countDown()方法,计数器减为0,await()方法返回,主线程继续执行。

  • 相关阅读:
    Vue--keep-alive--详解
    .NET高级调试之sos命令输出看不懂怎么办
    35岁测试工程师现状:被生活、房贷车贷压得喘不过气,哪敢谈什么追求~
    数据结构与算法(二) 概述
    数字式射频频率计的选择
    JS 模块化- 05 ES Module & 4 大规范总结
    Kafka(一)使用Docker Compose安装单机Kafka以及Kafka UI
    java基于BS结构的中俄师生学术交流平台
    101道算法JavaScript描述【二叉树】9
    Redis数据库持久化
  • 原文地址:https://blog.csdn.net/a1774381324/article/details/133717878