JUC之花里胡哨CountDownLatch

前言

CountDownLatch允许一个或多个线程等待其他线程完成操作。定义CountDownLatch的时候,需要传入一个正数来初始化计数器(虽然传入0也可以,但这样的话CountDownLatch没什么实际意义)。其countDown方法用于递减计数器,await方法会使当前线程阻塞,直到计数器递减为0。所以CountDownLatch常用于多个线程之间的协调工作。

示例

假设我们现在有这样一个需求:
由于很多群友在技术群搞黄色🍋,群主想了个办法

  1. 发布假资源,吸引🍋党的注意
  2. 统计名单
  3. 踢出群聊

过程如下所示:

public class CountDownLatchTest {
    private static ExecutorService ExecutorService = Executors.newFixedThreadPool(2);

    public static void main(String[] args) throws InterruptedException {
        // 1. 模拟从数据库获取数据
        String[] data = query();
        System.out.println("获取群友名单");

        // 2. 数据处理
        IntStream.range(0, data.length).forEach(i -> {
            ExecutorService.execute(() -> {
                
                if (i==1){
                    data[i] = "Yellow";
                }
                String value = data[i];
                System.out.println(value+"群友上车成功");
            });
        });
        System.out.println("所有群友都处理完了");
        // 关闭线程池
        ExecutorService.shutdown();
        // 3. 保存数据
        save(data);
    }
    private static String[] query() {
        return new String[]{"T", "B", "Y", "K"};
    }
    private static void save(String[] data) {
        System.out.println("踢出群聊名单 - " + Arrays.toString(data));
    }
}

由于线程获取CPU时间片的不确定性,所以有可能数据还没有处理完毕,导致没上勾就踢错

获取群友名单
所有群友都处理完了
踢出群聊名单 - [T, B, Y, K]
T群友上车成功
B群友上车成功
Y群友上车成功
K群友上车成功

CountDownLatch解决这个问题

public class CountDownLatchTest {
    private static ExecutorService ExecutorService = Executors.newFixedThreadPool(2);
    private static CountDownLatch latch = new CountDownLatch(4);

    public static void main(String[] args) throws InterruptedException {
        // 1. 模拟从数据库获取数据
        String[] data = query();
        System.out.println("获取群友名单");

        // 2. 数据处理
        IntStream.range(0, data.length).forEach(i -> {
            ExecutorService.execute(() -> {
                
                if (i==1){
                    data[i] = "Yellow";
                }
                String value = data[i];
                System.out.println(value+"群友上车成功");
                latch.countDown();
            });
        });
        latch.await(2, TimeUnit.SECONDS); // 最多等待 3秒
        System.out.println("所有群友都处理完了");
        // 关闭线程池
        ExecutorService.shutdown();
        // 3. 保存数据
        save(data);
    }
    private static String[] query() {
        return new String[]{"T", "B", "Y", "K"};
    }
    private static void save(String[] data) {
        System.out.println("踢出群聊名单 - " + Arrays.toString(data));
    }
}

定义一个CountDownLatch,计数器值为4,在每个线程执行完毕的时候调用countDown方法,让计数器减1。
main方法调用await方法让main线程阻塞等待,直到计数器被减为0。所以这就保证了只有当所有数据加工完毕才执行保存数据操作。
await有重载方法:await(long timeout, TimeUnit unit),设置最大等待时间,超过这个时间程序将继续执行不再被阻塞

获取群友名单
T群友上车成功
Y群友上车成功
K群友上车成功
Yellow群友上车成功
所有群友都处理完了
踢出群聊名单 - [T, Yellow, Y, K]

ok,群主的钓鱼执法成功!🌰

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值