【Java】CountDownLatch简单使用

学而不思则罔,思而不学则殆


CountDownLatch简单介绍

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

CountDownLatch不足

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

使用场景

使用多线程下载文件,每个线程下载一部分,当每个线程都下载完成时整个文件下载完成

简单测试

测试countDown

    private static void test1() {
        CountDownLatch countDownLatch = new CountDownLatch(3);
        System.out.println(System.currentTimeMillis() + " " + countDownLatch.getCount());
        countDownLatch.countDown();
        System.out.println(System.currentTimeMillis() + " " + countDownLatch.getCount());
        countDownLatch.countDown();
        System.out.println(System.currentTimeMillis() + " " + countDownLatch.getCount());
        countDownLatch.countDown();
        System.out.println(System.currentTimeMillis() + " " + countDownLatch.getCount());
        countDownLatch.countDown();

        try {
            System.out.println(System.currentTimeMillis() + " " + countDownLatch.getCount());
            countDownLatch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(System.currentTimeMillis() + " end");
    }

初始化了一个数量为3的计数器,调用四次countDown方法。
测试结果:

1603885038335 3
1603885038335 2
1603885038335 1
1603885038335 0
1603885038335 0
1603885038335 end

计数变为0后,调用countDown,还是0。调用await方法会立即成功(当前计数为0)。

测试多线程下载demo

    //模拟自下载下载文件
    static class DownloadTask implements Runnable {
        int downloadId;
        CountDownLatch countDownLatch;

        public DownloadTask(int downloadId, CountDownLatch countDownLatch) {
            this.downloadId = downloadId;
            this.countDownLatch = countDownLatch;
        }

        @Override
        public void run() {
            try {
                System.out.println(Thread.currentThread() + " " + System.currentTimeMillis() + " 开始下载-" + downloadId);
                // TODO: 2020/10/28 用休眠代替子线程执行耗时任务
                TimeUnit.SECONDS.sleep(new Random().nextInt(10));
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                countDownLatch.countDown();
                System.out.println(Thread.currentThread() + " " + System.currentTimeMillis() + " 下载结束-" + downloadId + " getCount:" + countDownLatch.getCount());
            }
        }
    }

    private static void test2() {
        final CountDownLatch countDownLatch = new CountDownLatch(3);
        ExecutorService executorService = Executors.newCachedThreadPool();
        executorService.submit(new DownloadTask(1, countDownLatch));
        executorService.submit(new DownloadTask(2, countDownLatch));
        executorService.submit(new DownloadTask(3, countDownLatch));

        try {
            System.out.println(Thread.currentThread() + " " + System.currentTimeMillis() + " 等待整个文件下载完成");
            countDownLatch.await();
            System.out.println(Thread.currentThread() + " " + System.currentTimeMillis() + " 整个文件下载完成 getCount:" + countDownLatch.getCount());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

测试结果:

Thread[main,5,main] 1603890741458 等待整个文件下载完成
Thread[pool-1-thread-1,5,main] 1603890741458 开始下载-1
Thread[pool-1-thread-2,5,main] 1603890741463 开始下载-2
Thread[pool-1-thread-3,5,main] 1603890741463 开始下载-3
Thread[pool-1-thread-3,5,main] 1603890746463 下载结束-3 getCount:2
Thread[pool-1-thread-2,5,main] 1603890748463 下载结束-2 getCount:0
Thread[main,5,main] 1603890748463 整个文件下载完成 getCount:0
Thread[pool-1-thread-1,5,main] 1603890748463 下载结束-1 getCount:0

当countDown等于0的时候,才会往下执行

await 超时逻辑

    private static void test3() {
        CountDownLatch countDownLatch = new CountDownLatch(1);
        ExecutorService executorService = Executors.newCachedThreadPool();
        executorService.submit(new Runnable() {
            @Override
            public void run() {
                try {
                    // TODO: 2020/10/28 执行耗时操作
                    TimeUnit.SECONDS.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(System.currentTimeMillis()+" countDown");
                countDownLatch.countDown();
            }
        });

        try {
            System.out.println(System.currentTimeMillis()+" await start");
            countDownLatch.await(5,TimeUnit.SECONDS);
            System.out.println(System.currentTimeMillis()+" await end");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

主线程等待5秒,但是子线程任务需要10秒才会完成,所以5秒过后,主线就不在等待。结果如下:

1603891276683 await start
1603891281688 await end
1603891286683 countDown
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值