广告
返回顶部
首页 > 资讯 > 后端开发 > Python >Java之CountDownLatch原理全面解析
  • 507
分享到

Java之CountDownLatch原理全面解析

JavaCountDownLatchCountDownLatch原理CountDownLatch原理解析 2022-11-13 18:11:56 507人浏览 独家记忆

Python 官方文档:入门教程 => 点击学习

摘要

目录CountDownLatch原理解析1. demo展示2. 原理解析Java CountDownLatch学习总结来源包业务书写示例一般代码示例CountDownLatch原理解

CountDownLatch原理解析

1. demo展示

代码逻辑展示了主线程中创建2个子线程分别去执行任务,主线程等2个子线程执行完毕后,再接着执行下面的代码;

常用场景:

分别计算,汇总结果。如,多个线程分别解析excel中的sheet,等待全部解析完毕后汇总结果;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

public class CountDownLatchDemo {
    //定义一个倒计时闩
    static CountDownLatch c = new CountDownLatch(2);

    public static void main(String[] args) throws InterruptedException {
        new Thread(() -> {
            try {
                TimeUnit.MICROSECONDS.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("我是线程1");
            //释放一个
            c.countDown();
        }).start();

        new Thread(() -> {
            try {
                TimeUnit.MICROSECONDS.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("我是线程2");
            //释放一个
            c.countDown();
        }).start();

        System.out.println("我是主线程,我要等那两个线程执行完毕...");
        //等待倒计时为0
        c.await();
        System.out.println("我是主线程,那两个线程都执行完了");
    }
}

输出:

我是主线程,我要等那两个线程执行完毕...

我是线程2

我是线程1

我是主线程,那两个线程都执行完了

2. 原理解析

1.先看构造函数new CountDownLatch(2)做了什么?

这是初始化了AQS子类,并将AQS的状态state设置为传入的2;

public CountDownLatch(int count) {
      if (count < 0) throw new IllegalArgumentException("count < 0");
      this.sync = new Sync(count);
  }

2.看c.countDown()做了什么?

它释放了一个共享锁状态,也就是state减1;

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

3.再看c.await()做了什么?

await方法是CounDownLatch中定义的,它调用了其内部类Sync(也是AQS的子类)的获取共享锁的方法acquireSharedInterruptibly;

acquireSharedInterruptibly方法中调用了CountDownLatch内部类Sync中实现的获取共享锁的方法tryAcquireShared,返回值不小0就算获取到了锁,await方法就能返回了,如果返回值小于0将会进入阻塞等待;

CountDownLatch内部类Sync中tryAcquireShared的实现很简单,只要state=0就返回1,否则返回-1;上面说了返回一个不小于0的数字,c.await()就相当于获取到了锁,就可以返回了,主线程就可以继续执行了。

通过上面分析,每次c.countDown(),就会将state减1,state=0的时候主线程恢复执行; 

Java CountDownLatch学习总结

来源包

同为 java.util.concurrent 下的,即也是并发多线程相关下的类,直译 “倒计时锁存器”,一般用于多线程场景,单一的线程也可以,用于等待多个任务完成后再执行其他操作;

提供方法

await()

  • 导致当前线程等待,直到锁存器倒数到零,除非该线程是{@linkplain Thread35;interrupt interrupted}即被打断状态。
  • 如果当前计数为零,则此方法立即返回。
  • 如果当前计数大于零,则当前线程将出于线程调度目的被禁用,并处于休眠状态,直到发生以下两种情况之一:
  • 由于调用{@link#countDown}方法,计数达到零;或者其他线程{@linkplain thread#中断}当前线程。

如果当前线程:

  • 在进入此方法时设置了其中断状态;或者
  • 在等待时{@linkplain Thread#interrupt interrupted},
  • 则抛出{@link InterruptedException},并清除当前线程的中断状态。

简单说就是当使用了这个方法后当前这一个线程将进入等待状态,直到计数器被减到0或者当前线程被中断,计数器被减到0后,所有等待的线程将被唤醒继续向下执行

await(long timeout, TimeUnit unit)

同上,但是指定了等待的超时时间,即线程除了上方两种被唤醒的情况下,等待到超时时间后也会被唤醒

  • countDown():当前计数器减一,如果如果减到 0 则唤醒所有等待在这个 CountDownLatch 上的线程。
  • getCount():获取当前计数的数值

业务书写示例

即将需要一会儿处理的业务 list 设置为计数器的大小,

然后对里面的业务数据执行异步操作,处理业务过程中不论是否有异常都需要对计数器减一,最终使用 await 等待所有任务执行完成,执行完成后,将进入后续处理

            final CountDownLatch latch = new CountDownLatch(lists.size());
            
            for (List<JSONObject> item: lists) {
                executor.submit(new Runnable() {
                    @Override
                    public void run() {
                        // ....... 业务处理
                        } catch (Exception e) {
                            // 异常处理
                        } finally {
                            latch.countDown();
                        }
                    }
                });
            }

            try {
                latch.await();
            } catch (InterruptedException e) {
                log.error("线程被中断", e);
            }

       // lists 处理完成后的其他业务操作

一般代码示例

public static void main(String[] args) throws InterruptedException {
        final CountDownLatch downLatch = new CountDownLatch(3);

        Await wait111 = new Await("wait111", downLatch);
        Await wait222 = new Await("wait222", downLatch);
        CountDownStart countDownStart = new CountDownStart(downLatch);

        wait111.start();
        wait222.start();
        Thread.sleep(1000);
        countDownStart.run();

    }


class Await extends Thread{

    private CountDownLatch countDownLatch;
    private String name;

    public Await(String name, CountDownLatch countDownLatch){
        this.name = name;
        this.countDownLatch = countDownLatch;
    }


    @Override
    public void run() {
        System.out.println(name + " start.....");
        System.out.println(name + " run.....");
        try {
            countDownLatch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(name + " continue.....run");
    }
}

class CountDownStart extends Thread{

    private CountDownLatch countDownLatch;

    public CountDownStart(CountDownLatch countDownLatch){
        this.countDownLatch = countDownLatch;
    }

    @Override
    public void run() {
        countDownLatch.countDown();
        countDownLatch.countDown();
        countDownLatch.countDown();
        System.out.println("start countDown");
    }
}

运行结果: 

wait222 start.....
wait222 run.....
wait111 start.....
wait111 run.....
start countDown
wait111 continue.....run
wait222 continue.....run
 

但是当我把线程等待去除后:

    public static void main(String[] args) throws InterruptedException {
        final CountDownLatch downLatch = new CountDownLatch(3);

        Await wait111 = new Await("wait111", downLatch);
        Await wait222 = new Await("wait222", downLatch);
        CountDownStart countDownStart = new CountDownStart(downLatch);

        wait111.start();
        wait222.start();
//        Thread.sleep(1000);
        countDownStart.run();

    }

结果:

start countDown
wait111 start.....
wait111 run.....
wait111 continue.....run
wait222 start.....
wait222 run.....
wait222 continue.....run

另外两个线程线程并没有开始就执行,可能被抢占了,也可能调度优先度不同,实际使用时还是需要多多实验

以上为个人经验,希望能给大家一个参考,也希望大家多多支持编程网。

--结束END--

本文标题: Java之CountDownLatch原理全面解析

本文链接: https://www.lsjlt.com/news/170319.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • Java之CountDownLatch原理全面解析
    目录CountDownLatch原理解析1. demo展示2. 原理解析Java CountDownLatch学习总结来源包业务书写示例一般代码示例CountDownLatch原理解...
    99+
    2022-11-13
    Java CountDownLatch CountDownLatch原理 CountDownLatch原理解析
  • Java并发编程之CountDownLatch源码解析
    目录一、前言二、使用三、源码分析四、总结一、前言 CountDownLatch维护了一个计数器(还是是state字段),调用countDown方法会将计数器减1,调用await方法会...
    99+
    2022-11-12
  • 全面解析@InsertProvider执行原理
    目录@InsertProvider执行原理1.首先要拼接处insert语句2.ProviderSqlSource实现了sqlSource接口关于@Insert和@InsertProv...
    99+
    2022-11-13
  • Java concurrency之CountDownLatch原理和示例_动力节点Java学院整理
    CountDownLatch简介CountDownLatch是一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待。 CountDownLatch和CyclicBarrier的区别(01) Coun...
    99+
    2023-05-31
    java concurrency countdownlatch
  • SpringBoot之webflux全面解析
    目录webflux介绍webflux应用场景Spring Boot 2.0 WebFlux响应式编程Spring Webfluxspring webflux和spring mvc的异...
    99+
    2022-11-13
  • 阿里四面之Spring Exception的原理解析
    错误场景 验证请求的Token合法性的Filter。Token校验失败时,直接抛自定义异常,移交给Spring处理: 测试HTTP请求: 日志输出如下:说明IllegalR...
    99+
    2022-11-12
  • Java面试高频问题之RabbitMQ系列全面解析
    1.RabbitMQ是什么? RabbitMQ是一款开源的,Erlang编写的,基于AMQP(高级消息队列协议)协议的消息中间件。 2.为什么要使用消息队列? 从本质上来说是因为互联...
    99+
    2022-11-12
  • Java全面分析面向对象之多态
    目录多态的理解向上转型向上转型的三种形式动态绑定和静态绑定方法的重写进一步认识和理解多态多态的优点多态的理解 什么是多态呢??从字面理解就是多种形态,也就是不同类实例化出来的对象调用...
    99+
    2022-11-13
  • Java全面分析面向对象之继承
    目录继承什么是继承呢?子类访问父类的成员变量子类访问父类非同名成员变量子类访问父类同名成员变量子类访问父类的成员方法子类访问父类的非同名方法子类访问父类的同名方法super关键字su...
    99+
    2022-11-13
  • Java全面分析面向对象之封装
    目录什么是封装呢封装的好处意义getter方法和setter方法toString方法面向对象封装之包自定义包什么是封装呢 封装就是一种将数据和操作数据的方法进行有机结合,一种函数抽象...
    99+
    2022-11-13
  • Python协程原理全面分析
    目录序章生成器如何进化为协程用作协程的生成器的基本行为协程的四个状态示例-使用协程计算平均值预激协程的装饰器终止协程和异常处理获取协程返回值使用yield fromyield fro...
    99+
    2023-02-08
    Python协程 Python协程原理
  • React框架核心原理全面深入解析
    目录前言第一章 基本概念第二章 createElement 函数第三章 render函数第四章 Concurrent Mode第五章 Fibers第六章 Render and Com...
    99+
    2022-11-16
    React框架的原理 React框架核心
  • Java基础夯实之线程问题全面解析
    目录1. 线程是什么2. 怎样创建线程2.1 继承Thread类2.2 实现Runnable接口2.3 实现Callable接口2.4 使用线程池创建3. 线程的状态4. 线程常用方...
    99+
    2022-11-13
    Java线程解析 Java线程
  • 全面解析Android之ANR日志
    目录一、概述二、ANR产生机制2.1 输入事件超时(5s)2.2 广播类型超时(前台15s,后台60s)2.3 服务超时(前台20s,后台200s)2.4 ContentProvid...
    99+
    2022-11-12
  • java面向对象设计原则之开闭原则示例解析
    概念 唯一不变的是不断的变化,在软件开发中应该对需求的变化持开放态度,我们要做的就是如何将这种变化对我们现有的成果带来最小的冲击。开闭原则直接面对面向对象程序的目标扩展性和可维护性,...
    99+
    2022-11-12
  • Java网络编程之UDP实现原理解析
    UDP实现通信非常简单,没有服务器,每个都是客户端,每个客户端都需要一个发送端口和一个接收端口。一个客户端向另一个客户端发送消息时,需要知道对方的IP和接收端口,所用到的类为Data...
    99+
    2022-11-12
  • Java CGLib动态代理机制(全面解析)
    一、首先说一下JDK中的动态代理:JDK中的动态代理是通过反射类Proxy以及InvocationHandler回调接口实现的但是,JDK中所要进行动态代理的类必须要实现一个接口,也就是说只能对该类所实现接口中定义的方法进行代理,这在实际编...
    99+
    2023-05-31
    java 动态代理 cglib
  • 全面解析SpringBoot自动配置的实现原理
    之前一直在用SpringBoot框架,一直感觉SpringBoot框架自动配置的功能很强大,但是并没有明白它是怎么实现自动配置的,现在有空研究了一下,大概明白了SpringBoot框架是怎么实现自动配置的功能,我们编写一个最简单的自动配置功...
    99+
    2023-05-31
    spring boot 配置
  • java注解的全面分析
    全面解析java注解Java中的常见注解 a.JDK中的注解    @Override 覆盖父类或者父接口的方法    @Deprecated 表示方法已经过时 &nbs...
    99+
    2023-05-31
    java 注解 ava
  • Java Spring AOP源码解析之事务实现原理
    目录不用Spring管理事务?编程式事务管理使用PlatformTransactionManager使用TransactionTemplate声明式事务管理使用@Transactio...
    99+
    2022-11-12
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作