【Java】【多线程】CountdownLatch使用方法说明

CountDownLatch基本概念

CountDownLatch是在java1.5被引入的,CountDownLatch是一个同步工具类,用来协调多个线程之间的同步(或者说是线程之间的通信)。 CountDownLatch能够使一个线程在等待另外一些线程完成其工作之后,再本线程继续执行。他使用一个计数器进行实现。当计数器为0时,表示所有的线程都已经完成一些任务,然后在CountDownLatch上等待的线程就可以恢复执行接下来的任务。

CountDownLatch重点方法介绍

  • public void countDown():构造函数中的数字减1(递减锁存器的计数),如果计数到达零,则释放所有等待(.await())的线程。如果当前计数大于零,则将计数减少.
  • public boolean await():
使当前线程在锁存器倒计数至零之前一直等待,除非线程被中断。 
如果当前计数为零,则此方法立即返回。 
如果当前计数大于零,则出于线程调度目的,将禁用当前线程,且在发生以下两种情况之一前,该线程将一直处于休眠状态:
1)由于调用 countDown() 方法,计数到达零;或者其他某个线程中断当前线程。 
2)如果当前线程在进入此方法时已经设置了该线程的中断状态;或者在等待时被中断,则抛出 InterruptedException,并且清除当前线程的已中断状态。 
  • public boolean await(long timeout,TimeUnit unit):
参数:
  timeout - 要等待的最长时间
  unit - timeout 参数的时间单位。 
返回:
  如果计数到达零,则返回 true;如果在计数到达零之前超过了等待时间,则返回 false 
异常: 
   InterruptedException - 如果当前线程在等待时被中断

CountDownLatch适用场景说明

CountdownLatch核心两个作用:

  1. 多个线程等待同一个信号量一起工作。模拟真实并发的场景。
  2. 多个线程全部做完了,才开始做主线程工作。

下面的使用案例部分讲使用代码讲解CountDownLatch的使用案例

CountDownLatch使用案例

案例场景:百米赛跑,4名运动员选手到达场地等待裁判口令,裁判一声口令,选手听到后同时起跑,当所有选手到达终点,裁判进行汇总排名.(注意线程池的初始大小数量4)

public class CountdownLatchDemo {
    public static void main(String[] args) {

        /** 线程池使用规范见:本子包中的TreadPoolDemo类 */
        ThreadFactory namedThreadFactory = new ThreadFactoryBuilder().setNameFormat(" %d号运动员 ").build();
        ExecutorService threadPool =
                new ThreadPoolExecutor(4,8,0L,TimeUnit.MILLISECONDS,
                    new LinkedBlockingQueue<>(1024),namedThreadFactory,
                    new ThreadPoolExecutor.AbortPolicy());

        final CountDownLatch cdOrder = new CountDownLatch(1);
        final CountDownLatch cdPlayers = new CountDownLatch(4);
        for (int i = 0; i < 4; i++) {
            Runnable runnable = () -> {
                try {
                    System.out.println("选手" + Thread.currentThread().getName() + "正在等待裁判发布口令");
                    cdOrder.await();
                    System.out.println("选手" + Thread.currentThread().getName() + "已接受裁判口令");
                    Thread.sleep((long) (Math.random() * 10000));
                    System.out.println("选手" + Thread.currentThread().getName() + "到达终点");
                    cdPlayers.countDown();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    System.out.println("线程出现了异常"+e.getMessage());
                }
            };
            threadPool.execute(runnable);
        }
        try {
            Thread.sleep((long) (Math.random() * 10000));
            System.out.println("裁判"+Thread.currentThread().getName()+"即将发布口令");
            cdOrder.countDown();
            System.out.println("裁判"+Thread.currentThread().getName()+"已发送口令,正在等待所有选手到达终点");
            cdPlayers.await();
            System.out.println("所有选手都到达终点");
            System.out.println("裁判"+Thread.currentThread().getName()+"汇总成绩排名");
        } catch (InterruptedException e) {
            e.printStackTrace();
            System.out.println("线程出现了异常"+e.getMessage());
        }
        threadPool.shutdown();
    }
}

运行结果查看

选手 2号运动员 正在等待裁判发布口令
选手 0号运动员 正在等待裁判发布口令
选手 3号运动员 正在等待裁判发布口令
选手 1号运动员 正在等待裁判发布口令
裁判main即将发布口令
裁判main已发送口令,正在等待所有选手到达终点
选手 2号运动员 已接受裁判口令
选手 1号运动员 已接受裁判口令
选手 3号运动员 已接受裁判口令
选手 0号运动员 已接受裁判口令
选手 3号运动员 到达终点
选手 1号运动员 到达终点
选手 0号运动员 到达终点
选手 2号运动员 到达终点
所有选手都到达终点
裁判main汇总成绩排名

最后各位读者思考或者验证下面2种情况
1:如果将代码中第7行的new ThreadPoolExecutor(4, 修改成 new ThreadPoolExecutor(3, 会有什么结果输出?为什么?
2:本示例代码没有将裁判开始枪响 作为 运动员开始的信号量,如果要这样修改,需要怎么做呢? 动手试试吧。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值