Java并发编程之CountDownLatch

Java并发编程之CountDownLatch,第1张

Java并发编程之CountDownLatch

目录

一、概述

二、CountDownLatch与join的异同

三、源码解析

3.1、await方法源码解析

3.2、downCount方法源码解析


一、概述

作用:可以用来确保某些活动直到其他活动都完成后才继续执行。它是一个同步工具,一般被称作"计数器",作用大致就是数量达到了某个点之后计数结束,才能继续往下走。可以用作流程控制之类的作用,主流程分成多个子流程,然后主流程在子流程全部结束之前不动(子流程最好是相互独立的,除非能很好的控制两个流程的关联关系),子流程全部结束后主流程开始 *** 作。
应用场景:CountDownLatch非常适合于对任务进行拆分,使其并行执行,比如某个任务执行2s,其对数据的请求可以分为五个部分,那么就可以将这个任务拆分为5个子任务,分别交由五个线程执行,执行完成之后再由主线程进行汇总,此时,总的执行时间将决定于执行最慢的任务,平均来看,还是大大减少了总的执行时间。

使用说明:

CountDowmLatch是一种灵活的闭锁实现,包含一个计数器,该计算器初始化为一个正数,表示需要等待事件的数量。countDown方法递减计数器,表示有一个事件发生,而await方法等待计数器到达0,表示所有需要等待的事情都已经完成。

1. 在一组执行 *** 作的多个线程中,当完成了指定 *** 作后,就调用 CountDownLatch 实例的 downCount() 方法,将里面的计数器进行减一的 *** 作,当count==0时,会唤醒正在等待的线程
2. 在需要等待的线程中,通过调用 await() 方法进行等待,直到count ==0 后,等待线程继续往后执行。
PS: 注意downCount() 方法最好是在finally 中被调用, 否则容易因为异常而导致count 不能被赋值成0,从而等待线程一直被阻塞等待。

使用步骤:

1、主线程和子线程都有一个CountDowmLatch类型的成员变量;

2、new一个CountDowmLatch对象countDowmLatch,在创建主线程和子线程时都将countDowmLatch对象作为参数传入;

3、在主线程中调用await方法,countDowmLatch.await();

4、在子线程中调用downCount方法,countDowmLatch.downCount();

注意事项:

使用CountDownLatch必须确保计数器数量与子线程数量一致,且countDown必须要执行,否则出现计数器不为0,导致主线程一致等待的情况。

在执行任务的线程中,使用了try...finally结构,该结构可以保证创建的线程发生异常时CountDownLatch.countDown()方法也会执行,也就保证了主线程不会一直处于等待状态。

示例代码:

package com.flychuer.demo3;

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

public class CountDownLatchTest {

	public static void main(String[] args) throws InterruptedException {

        //CountDownLatch的计数器数量必须与线程的数量一致,否则可能出现一直等待的情况,即计数器不为0的情况
        //使用CountDownLatch 需要注意,子线程中的countDown()最好放到finnally里面,防止计数器不为0
        CountDownLatch latch = new CountDownLatch(3);

        ExecutorService ex = Executors.newCachedThreadPool();
        ex.execute(new Worker(latch));
        ex.execute(new Worker(latch));
        ex.execute(new Worker(latch));
        
        System.out.println("主线程等待子线程执行");

        //latch.await(1,TimeUnit.SECONDS);//模拟超时等待的情况
        latch.await(); //模拟等待的情况,不考虑子线程的处理实际
        System.out.println("主线程开始执行");
        ex.shutdown();
    }

}

class Worker implements Runnable {

    CountDownLatch lanch;

    public Worker() {

    }

    public Worker(CountDownLatch lanch) {
        this.lanch = lanch;
    }

    @Override
    public void run() {
        try {
            Thread.sleep(2000L);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getId()+":子线程正在执行");
        lanch.countDown();
    }
}

结果:

主线程等待子线程执行
11:子线程正在执行
10:子线程正在执行
12:子线程正在执行
主线程开始执行

二、CountDownLatch与join的异同

相同点:

都可以实现主线程等待其它子线程执行完成后,再继续执行的功能。

不同点:

1、join是Thread类的一个方法;CountDownLatch是一个类。

2、join()的阻塞原理是不停检查join()所属的线程对象是否存活(也就是线程完全执行完毕),如果存活则让调用join()的线程保持阻塞。

3、CountDownLatch的阻塞原理是仅仅关注计数器是否为0,若为0才保持阻塞,它并不关注持有计数器的其它线程是否完全执行完毕。

4、CountDownLatch更灵活,它可以只等待子线程执行一部分,而不是等子线程全部执行完成。例如,子线程分为两步,可以在完成第一步后调用downCount()。

三、源码解析 3.1、await方法源码解析

3.2、downCount方法源码解析

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5637065.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-16
下一篇 2022-12-16

发表评论

登录后才能评论

评论列表(0条)

保存