Java并发系列之五 CountDownLatch源码解析

本文涉及的产品
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: Java并发系列之五 CountDownLatch源码解析

CountDownLatch概述



引用一段CountDownLatch类注释


A synchronization aid that allows one or more threads to wait until a set of operations being performed in other threads completes.


CountDownLatch是一个同步辅助类。它可以让一个或者多个线程一直阻塞直到其他线程完成了一些指定的操作。


下面我用一个实战案例来说明下CountDownLatch的使用。开启了5个线程去爬取网络上的数据。当爬取完N条数据时,爬取任务停止,让其他线程去汇总这N条数据。

public class CountDownLatchUsage {
    private final static int TASK_COUNT = 100;
    private volatile int count = 0;
    private CountDownLatch countDownLatch = new CountDownLatch(TASK_COUNT);
    private Runnable runnable = new Runnable() {
        @Override
        public void run() {
            while (true) {
                System.out.println("爬取数据中---");
                count++;
                countDownLatch.countDown();
                if (count == TASK_COUNT) break;
            }
        }
    };
    public static void main(String[] args) {
        final CountDownLatchUsage usage = new CountDownLatchUsage();
        ExecutorService service = Executors.newFixedThreadPool(5);
        service.submit(usage.runnable);
        new Thread(){
            @Override
            public void run() {
                super.run();
                try {
                    //这里加一个await()完美的解释了让多个线程阻塞
                    usage.countDownLatch.await();
                    System.out.println("子线程开始做任务");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }.start();
        try {
            usage.countDownLatch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("对数据做汇总 - " + usage.count);
    }
}

…….忽略 97条打印结果


获取到一条数据


获取到一条数据


获取到一条数据


子线程开始做任务


对数据做汇总 - 100


由结果可以看出 主线程和子线程都会等线程池打印完100条数据后打印


源码解析



CountDownLatch内部使用的是 共享锁。当线程调用CountDownLatch的await()。其实线程就是在获取共享锁。CountDownLatch(int count) 构造函数 count参数就是初始化了内部共享锁的Sync的state值。获取到共享锁的条件就是 state == 0。countDown()就是释放共享锁,主要是让state-1。如果执行了count次countDown()。state就等于0。在CountDownLatch上等待的线程将获取共享锁。


1. await()方法

public void await() throws InterruptedException {
        //获取共享锁
        sync.acquireSharedInterruptibly(1);
}
protected int tryAcquireShared(int acquires) {
        //当state==0的时候才能获取到锁
        return (getState() == 0) ? 1 : -1;
}

如果CountDownLatch(int count)构造函数 传入的count>0

只要线程调用了await()方法,那么该线程都会进入AQS的队列中等待。并且阻塞线程。那么只有当CountDownLatch调用了countDown()方法,并且state==0时,线程才能重新唤醒。


2. countDown()方法


public void countDown() {
    sync.releaseShared(1);
}

countDown()方法主要就是用来释放共享锁的。当然这里可能有的读者会有疑问。共享锁不是没有获取到吗,怎么还能释放呢。其实呢这里主要是将state-1了,并且唤醒AQS中等待的线程,自旋获取共享锁.

相关文章
|
2天前
|
存储 Java 编译器
Java内存模型(JMM)深度解析####
本文深入探讨了Java内存模型(JMM)的工作原理,旨在帮助开发者理解多线程环境下并发编程的挑战与解决方案。通过剖析JVM如何管理线程间的数据可见性、原子性和有序性问题,本文将揭示synchronized关键字背后的机制,并介绍volatile关键字和final关键字在保证变量同步与不可变性方面的作用。同时,文章还将讨论现代Java并发工具类如java.util.concurrent包中的核心组件,以及它们如何简化高效并发程序的设计。无论你是初学者还是有经验的开发者,本文都将为你提供宝贵的见解,助你在Java并发编程领域更进一步。 ####
|
4天前
|
消息中间件 缓存 安全
Future与FutureTask源码解析,接口阻塞问题及解决方案
【11月更文挑战第5天】在Java开发中,多线程编程是提高系统并发性能和资源利用率的重要手段。然而,多线程编程也带来了诸如线程安全、死锁、接口阻塞等一系列复杂问题。本文将深度剖析多线程优化技巧、Future与FutureTask的源码、接口阻塞问题及解决方案,并通过具体业务场景和Java代码示例进行实战演示。
21 3
|
6天前
|
Java 程序员 开发者
Java中的异常处理机制深度解析####
本文将深入浅出地探讨Java编程语言中异常处理的核心概念与实践策略,旨在帮助开发者更好地理解如何构建健壮的应用程序。通过剖析异常体系结构、掌握有效的异常捕获与处理技巧,以及学习最佳实践,读者能够提升代码质量,减少运行时错误,从而增强软件的稳定性和用户体验。 ####
|
4天前
|
Java 数据库连接 数据库
如何构建高效稳定的Java数据库连接池,涵盖连接池配置、并发控制和异常处理等方面
本文介绍了如何构建高效稳定的Java数据库连接池,涵盖连接池配置、并发控制和异常处理等方面。通过合理配置初始连接数、最大连接数和空闲连接超时时间,确保系统性能和稳定性。文章还探讨了同步阻塞、异步回调和信号量等并发控制策略,并提供了异常处理的最佳实践。最后,给出了一个简单的连接池示例代码,并推荐使用成熟的连接池框架(如HikariCP、C3P0)以简化开发。
15 2
|
5天前
|
存储 缓存 安全
🌟Java零基础:深入解析Java序列化机制
【10月更文挑战第20天】本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
14 3
|
4天前
|
算法 Java 数据库连接
Java连接池技术,从基础概念出发,解析了连接池的工作原理及其重要性
本文详细介绍了Java连接池技术,从基础概念出发,解析了连接池的工作原理及其重要性。连接池通过复用数据库连接,显著提升了应用的性能和稳定性。文章还展示了使用HikariCP连接池的示例代码,帮助读者更好地理解和应用这一技术。
15 1
|
安全 Java
Java并发编程笔记之CopyOnWriteArrayList源码分析
并发包中并发List只有CopyOnWriteArrayList这一个,CopyOnWriteArrayList是一个线程安全的ArrayList,对其进行修改操作和元素迭代操作都是在底层创建一个拷贝数组(快照)上进行的,也就是写时拷贝策略。
19547 0
|
Java 安全
Java并发编程笔记之读写锁 ReentrantReadWriteLock 源码分析
我们知道在解决线程安全问题上使用 ReentrantLock 就可以,但是 ReentrantLock 是独占锁,同时只有一个线程可以获取该锁,而实际情况下会有写少读多的场景,显然 ReentrantLock 满足不了需求,所以 ReentrantReadWriteLock 应运而生,ReentrantReadWriteLock 采用读写分离,多个线程可以同时获取读锁。
3131 0
|
Java
Java并发编程笔记之FutureTask源码分析
FutureTask可用于异步获取执行结果或取消执行任务的场景。通过传入Runnable或者Callable的任务给FutureTask,直接调用其run方法或者放入线程池执行,之后可以在外部通过FutureTask的get方法异步获取执行结果,因此,FutureTask非常适合用于耗时的计算,主线程可以在完成自己的任务后,再去获取结果。
4292 0
|
Java 调度 API
Java并发编程笔记之Timer源码分析
timer在JDK里面,是很早的一个API了。具有延时的,并具有周期性的任务,在newScheduledThreadPool出来之前我们一般会用Timer和TimerTask来做,但是Timer存在一些缺陷,为什么这么说呢?   Timer只创建唯一的线程来执行所有Timer任务。
3002 0

推荐镜像

更多