java多线程:17、J.U.C之CountDownLatch

介绍

CountDownLatch是一个计数的闭锁,作用与CyclicBarrier有点儿相似。

在API中是这样描述的:

用给定的计数 初始化 CountDownLatch。由于调用了 countDown() 方法,所以在当前计数到达零之前,调用await 方法的线程会一直受阻塞。当计数到达零时,会释放所有等待的线程,await 的所有后续调用都将立即返回。

这种现象只出现一次——计数无法被重置。如果需要重置计数,请考虑使用 CyclicBarrier。

  • CountDownLatch:一个或者多个线程等待其他多个线程完成某件事情之后才能执行,等待的线程通过调用await方法,其他线程完成了某件事后调用countDown方法递减
  • CyclicBarrier:多个线程互相等待,直到到达同一个同步点,再继续一起执行。可以通过构造方法指定一个线程,当等待的线程满足条件就会优先执行这个线程,

对于CountDownLatch来说,重点是“一个线程或多个线程等待”,等待指定的线程数量完成“某件事情”之后,可以终止,也可以等待。而对于CyclicBarrier,重点是多个线程中若任意一个线程没有完成,所有的线程都必须等待。

CountDownLatch是通过一个计数器来实现的,计数器的初始值为线程的数量。每当一个线程完成了自己的任务后,计数器的值就会减1。当计数器值到达0时,它表示所有的线程已经完成了任务,然后就可以恢复等待的线程继续执行了。如下图

在这里插入图片描述

实现分析

CountDownLatch结构如下

在这里插入图片描述

通过上面的结构图我们可以看到,CountDownLatch内部依赖Sync实现,而Sync继承AQS

构造方法

CountDownLatch仅提供了一个构造方法:

  • CountDownLatch(int count) : 构造一个用给定计数初始化的 CountDownLatch
public CountDownLatch(int count) {
    if (count < 0) throw new IllegalArgumentException("count < 0");
    this.sync = new Sync(count);
}

Sync为CountDownLatch的一个内部类,通过这个内部类Sync可以知道CountDownLatch是采用共享锁来实现的

常用方法

  • await() (注意不是wait方法):使当前线程在锁存器倒计数至零之前一直等待,除非线程被中断。内部使用AQS的getState方法获取计数器,如果计数器值不等于0,则会以自旋方式会尝试一直去获取同步状态。
  • countDown():递减锁存器的计数,如果计数到达零,则释放所有等待的线程。内部调用AQS的releaseShared(int arg)方法来释放共享锁同步状态。

案例

在CyclicBarrier应用场景之上进行修改,添加接力运动员。

起点运动员应该等其他起点运动员准备好才可以起跑(CyclicBarrier)。

接力运动员不需要关心其他人,只需和自己有关的起点运动员到接力点即可开跑(CountDownLatch)。

    public static void main(String[] args) {
        CyclicBarrier cyclicBarrier = new CyclicBarrier(10,()->{
            System.out.println("-----------------------五个运动员和五个接力运动员都已全部就位,开跑--------------");
        });

        List<Thread> threads = new ArrayList<>();

        for (int i = 0; i < 5; i++) {
            CountDownLatch countDownLatch = new CountDownLatch(1);
            threads.add(new Thread(()->{
                try {
                    System.out.println(Thread.currentThread().getName() + "--->已到位");
//                    等待其他运动员
                    cyclicBarrier.await();
                    System.out.println(Thread.currentThread().getName() + "--->已到达交接点");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (BrokenBarrierException e) {
                    e.printStackTrace();
                }finally {
//                    通知接力运动员
                    countDownLatch.countDown();
                }
            },"运动员:"+i));
            threads.add(new Thread(()->{
                try {
                    System.out.println(Thread.currentThread().getName() + "--->已到位");
//                    等待其他接力运动员
                    cyclicBarrier.await();
//                    等待起跑运动员给我棒子
                    countDownLatch.await();
                    System.out.println("恭喜 " + Thread.currentThread().getName() + "---> 到达交接点");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (BrokenBarrierException e) {
                    e.printStackTrace();
                }
            },"接力运动员:"+i));
        }
        for (Thread thread : threads) {
            thread.start();
        }
    }

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值