Java多线程实现-CountDownLatch

18 阅读2分钟

CountDownLatch介绍

去其他地方看吧

CountDownLatch常用接口:

  1. 构造函数创建CountDownLatch对象:

    CountDownLatch countDownLatch = new CountDownLatch(num);

    输入初始倒计时开始数据,也是需要执行的任务数量

  2. countDown() : 多线程中使用,线程任务结束时执行,num--,表示一个线程任务的结束。

  3. await() : 阻塞主线程,等待多个线程任务执行完成,再继续后续的操作。

常见业务场景

  1. 一等多:主线任务等待多个支线任务执行完成再走流程。比如:人满发车(每个座位是支线任务,发车是主线任务)
  2. 多等一:多个任务等待主线任务完成再开始执行。比如:长跑比赛,枪响开跑,跑完比赛结束。

CountDownLatch对于多线程的实现

CountDownLatch本身是单线程的,如果要进行多线程操作,需要搭配线程池

代码实现


package CountDownLatchDemo;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class CountDownLatchDemo {
    public static void main(String[] args) throws InterruptedException {
        OneWaitMore();
        MoreWaitOne();
    }

    /**
     * 场景:一个等多个
     * 比如:人满发车
     */
    private static void OneWaitMore() {
        int seatCount = 20; // 座位数量
        // 设置计时器倒计时座位剩余的数量
        CountDownLatch countDownLatch = new CountDownLatch(seatCount);

        // 创建线程池,实现多线程执行
        int cpuCount = Runtime.getRuntime().availableProcessors();
        ExecutorService executorService = Executors.newFixedThreadPool(cpuCount * 2 + 1);
        for (int i = 0; i < seatCount; i++) {
            int tmp = i;
            executorService.execute(new Runnable() {
                @Override
                public void run() {
                    try {
                        Thread.sleep(1000);
                        System.out.println("座位" + tmp + "已经被占");
                    } catch (InterruptedException e) {
                        System.out.println("座位出现异常,无法落座");
                    }finally {
                        countDownLatch.countDown();
                    }
                }
            });
        }
        // 所有座位被占满之前,等待
        try {
            countDownLatch.await();
        } catch (InterruptedException e) {
            System.out.println("等待过程出现异常");
        }

        if (countDownLatch.getCount() == 0) {
            System.out.println("车已做满,开始发车");
        }else {
            System.out.println("不会走到这里的。。。");
        }
    }

    /**
     * 场景:多等一
     * 比如:长跑比赛,枪响开跑,跑完比赛结束。
     */
    private static void MoreWaitOne() throws InterruptedException {
        CountDownLatch startSignal = new CountDownLatch(1);

        int athleteCount = 10; // 参加比赛的远动员数量
        CountDownLatch athletes = new CountDownLatch(athleteCount);
        // 运动员准备过程:创建多个线程
        for (int i = 0; i < athleteCount; i++) {
            int tmp = i;
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        startSignal.await(); // 等待枪响的信号
                        Thread.sleep(10); // 完成跑程的时长
                        System.out.println(tmp+"号运动员到达终点");
                        athletes.countDown();
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                }
            }).start();
        }

        Thread.sleep(3);
        System.out.println("比赛倒计时 : 1");
        Thread.sleep(3);
        System.out.println("比赛倒计时 : 2");
        Thread.sleep(3);
        System.out.println("比赛倒计时 : 3");
        startSignal.countDown();
        System.out.println("比赛开始");
        athletes.await();
        System.out.println("比赛结束");
    }
}

代码执行接口:

image.png