countdownlatch

2022/12/22

前言: 一个使用场景,例如分发10个线程,需要等到这10个线程全部都执行完毕后,再进行下一步的处理。

看到过一个例子:举行跑步比赛,发令枪响后,几位选手开始跑步,当最后一位选手跑完全程,然后开始公布选手成绩、以及颁奖仪式。

  1. 模拟多个线程同时执行的场景
  2. 模拟依赖场景,例如一个数据的计算需要很多数据来源,需要这些数据来源全部加载完毕后才开始进行计算。

主要方法

  1. int getCount
  2. await()
public class LatchTest {

    private static final Logger LOGGER = Logger.getLogger("LatchTest");

    @Test
    public void test() {

        CountDownLatch latch = new CountDownLatch(1);

        for (int i = 0; i < 10; i++) {
            new Thread(deal(i, latch)).start();
        }

        LOGGER.info("3秒后开始....");
        SleepUtil.sleep(3000);
        latch.countDown();
    }

    private Runnable deal(int threadNum, CountDownLatch latch) {

        return new Runnable() {
            @Override
            public void run() {

                try {
                    latch.await();

                    LOGGER.info("开始运行...");
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        };
    }

    @Test
    public void test2() {
        CountDownLatch latch = new CountDownLatch(10);

        for (int i = 0; i < 10; i++) {
            new Thread(deal2(i, latch)).start();
        }

        LOGGER.info("等待加载中...");
        try {
            latch.await();

            LOGGER.info("开始进入主界面");
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }

    private Runnable deal2(int threadNum, CountDownLatch latch) {

        return new Runnable() {
            @Override
            public void run() {

                try {
                    LOGGER.info(threadNum + "开始运行");
                    SleepUtil.sleep(1000);
                    LOGGER.info(threadNum + "运行结束");
                } catch (Exception e) {
                } finally {
                    latch.countDown(); // 放在finally语句块中,无论程序正常执行还是出现异常,都会执行
                }
            }
        };
    }
}