并发编程系列之CountDownLatch用法简介

x33g5p2x  于2021-12-30 转载在 其他  
字(2.4k)|赞(0)|评价(0)|浏览(330)

1、 CountDownLatch倒计数锁存器

CountDownLatch:用于协同控制一个或多个线程等待在其他线程中执行的一组操作完成,然后再继续执行

2、 CountDownLatch用法

  • 构造方法:CountDownLatch(int count),count指定等待的条件数(任务数、操作数),不可再更改
  • 等待方法:await(),阻塞等待线程直到count减少为0,count为0时,不会阻塞,继续执行
  • boolean await(long timeout,TimeUnit unit):可以设置超时时间的await方法,返回true表示等待条件到达;false表示条件未来到达,但超时了
  • long getCount():获取当前计数值,常用于调试或者测试
    CountDownLatch注意事项:只可使用一次,不能重复使用,计数变为0之后,就不可再用

3、CountDownLatch适用场景

  1. 等待多个条件完成,countDownLatch(N)这个多个条件可以是:等待N个线程、等待N个操作、等待某操作的N次执行
  2. 用于并发测试,等待多个线程一起出发

4、CountDownLatch例子

例子:等待n个线程执行完成,再一起执行

import java.util.Random;
import java.util.concurrent.CountDownLatch;

public class CountDownLatchExample {

    public static void main(String[] args) {

        final CountDownLatch cdl = new CountDownLatch(1);

        int concurrency = 100;
        final Random random = new Random();
        for (int i = 0; i < concurrency; i++) {
            new Thread(()->{
                try {
                    Thread.sleep(random.nextInt(10_000));
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + "准备就绪");
                // 让并发线程都等待发出信号
                try {
                    cdl.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + "开始工作");
            }).start();
        }
        System.out.println("******************** 发出开始信号***********");
        cdl.countDown();
    }
}

执行,发现结果不符合我们的要求,虽然也是多个线程等待,再一起无序执行:

******************** 发出开始信号***********
Thread-22准备就绪
Thread-22开始工作
Thread-45准备就绪
Thread-45开始工作
...

因为CountDownLatch不能重用,所以再新加一个CountDownLatch协同N个线程:

import java.util.Random;
import java.util.concurrent.CountDownLatch;

public class StartTogerCountdownLatchExample {

    public static void main(String[] args) throws InterruptedException {
        final CountDownLatch cdl = new CountDownLatch(1);
        int concurrency = 100;
        final CountDownLatch cdln = new CountDownLatch(concurrency);
        final Random random = new Random();
        for (int i = 0;i < concurrency; i++) {
            new Thread(()->{
                try {
                    Thread.sleep(random.nextInt(10_000));
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(
                        Thread.currentThread().getName() + " 准备就绪");
                // 调用countDown()报告完成任务
                cdln.countDown();
                // 让所有线程都等待发出信号
                try {
                    cdl.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(
                        Thread.currentThread().getName() + " 开始工作");
            }).start();
        }
        //等待准备完成
        cdln.await();
        System.out.println("******************** 发出开始信号***********");
        cdl.countDown();
    }
}

等待N个线程准备就绪,然后一个总的CountDownLatch发出信号量,所有线程一起执行

...
Thread-11 准备就绪
Thread-14 准备就绪
Thread-53 准备就绪
Thread-91 准备就绪
******************** 发出开始信号***********
Thread-97 开始工作
Thread-57 开始工作
...

相关文章