Java 线程: CountDownLatch(最详解)

Java 线程:countDownLatch

点个赞吧 ☞

1. 背景

  • countDownLatch是在java1.5被引入,跟它一起被引入的工具类还有CyclicBarrierSemaphoreconcurrentHashMapBlockingQueue
  • 存在于java.util.cucurrent包下。

2. 概念

  • CountDownLatch是一个同步工具类,用来协调多个线程之间的同步,或者说起到线程之间的通信(而不是用作互斥的作用)。

  • CountDownLatch能够使一个线程在等待另外一些线程完成各自工作之后,再继续执行。使用一个计数器进行实现。计数器初始值为线程的数量。当每一个线程完成自己任务后,计数器的值就会减一。当计数器的值为0时,表示所有的线程都已经完成一些任务,然后在CountDownLatch上等待的线程就可以恢复执行接下来的任务。

3. 源码

  • countDownLatch类中只提供了一个构造器:

    // 参数count为计数值
    public CountDownLatch(int count) {  };  
    
  • 类中有三个最重要的方法是:

    	// 调用await()方法的线程会被挂起,它会等待直到count值为0才继续执行
    	public void await() throws InterruptedException { };   
    
    	/**
         * 等待一定的时间后count值还没变为0的话就会继续执行
         * @param timeout 要等待的最长时间
         * @param unit    参数的时间单位
         * @return   如果计数到达零,则返回 true;如果在计数到达零之前超过了等待时间,则返回 false
         * @throws InterruptedException
         */
        public boolean await(long timeout, TimeUnit unit) throws InterruptedException { };
    
    	// 将count值减1
    	public void countDown() { }; 
    

    使当前线程在锁存器倒计数至零之前一直等待,除非线程被中断或超出了指定的等待时间。如果当前计数为零,则此方法立刻返回 true 值。 如果当前计数大于零,则出于线程调度目的,将禁用当前线程,且在发生以下三种情况之一前,该线程将一直处于休眠状态

    • ​ 由于调用 countDown() 方法,计数到达零
    • ​ 其他某个线程中断当前线程;
    • 已超出指定的等待时间。

    如果计数到达零,则该方法返回 true 值。

    如果当前线程:

    • ​ 在进入此方法时已经设置了该线程的中断状态;
    • ​ 在等待时被中断

    则抛出 InterruptedException,并且清除当前线程的已中断状态。

    如果超出了指定的等待时间,则返回值为 false

4. 用法

  1. 某一线程在开始运行前等待n个线程执行完毕

  2. 实现多个线程开始执行任务的最大并行性

    注意是并行性,不是并发,强调的是多个线程在某一时刻同时开始执行。

5. 不足

​ CountDownLatch是一次性的,计算器的值只能在构造方法中初始化一次,之后没有任何机制再次对其设置值,当CountDownLatch使用完毕后,它不能再次被使用。

6. 示例

假设某公司需召开一个视频会议,共有10名高管参会,只有所有高管均到场后会试才开始

/**
 * @author hz
 * @blog www.huangzun.top
 * @date 2020/4/12
 */
public class CountDownLatchTest {
    public static void main(String[] args) {
        final CountDownLatch latch = new CountDownLatch(10);

        for (int i = 0; i < 10; i++) {
            ExecutorService es = Executors.newCachedThreadPool();
            String num = i + "";
            es.execute(() -> {
                try {
                    // 模拟公司高管到会不同的时间
                    Thread.sleep((int) (Math.random() * 10 * 1000));
                    Thread.currentThread().setName("boos-" + num);
                    System.out.println("高管(子线程):"+Thread.currentThread().getName()+" 到会!");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                latch.countDown();
            });
            es.shutdown();
        }
        System.out.println("等待所有人到齐...");

        try {
            latch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("所有人到齐,会议开始");
    }
}	

运行结果

在这里插入图片描述

6. CountDownLatch和CyclicBarrier区别

  • countDownLatch是一个计数器,线程完成一个记录一个,计数器递减,只能只用一次
  • CyclicBarrier的计数器更像一个阀门,需要所有线程都到达,然后继续执行,计数器递增,提供reset功能,可以多次使用

码云仓库

  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值