栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

CountDownLatch和CyclicBarrier的区别

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

CountDownLatch和CyclicBarrier的区别

一、前言

在JDK的并发包里提供了几个非常有用的并发工具类。如线程等待的CountDownLatch和CyclicBarrier。

二、等待多线程完成的CountDownLatch

CountDownLatch允许一个或多个线程等待其他线程完成操作后再执行后续的代码。

2.1 应用场景
  • 1个线程等多个线程:当程序需要从3个接口获取数据的时候,可以同时开3个线程去获取数据,等数据都获取到了,主线程再进行下一步操作。
  • 1个线程等多个线程:解析Excel的多个shell页,可以开多个线程去读取。
  • 多个线程等待:如秒杀场景同时让一组数据同时等待,同时恢复。
2.2 解析Excel的Shell页代码 2.2.1 主要的方法

countDown(): 将CountDownLatch对象内部维护的state变量减1。

wait():等待CountDownLatch对象内部维护的state变量减为0之后再往下执行代码。

public void getShellData(){
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(5, 10, 10, TimeUnit.MINUTES, new ArrayBlockingQueue<>(5));
        CountDownLatch latch = new CountDownLatch(5);
        List shellDataList = new ArrayList<>();
        for (int i = 0; i < 5; i++) {
            int finalI = i;
            threadPoolExecutor.execute(()->{
                shellDataList.add(getShellData(finalI));
                latch.countDown();
            });
        }
        latch.wait();
        // 5个shell页的数据都获取完了,再对汇总后的数据进行处理
        doOtherByShellDataList(shellDataList);
    }
2.3 死锁问题

如果线程池中线程的数量较少,在高并发时会出现多个请求占用了全部的线程,但是每个请求又需要await其他线程,被等待的线程拿不到线程资源无法执行,导致多个请求同时进入线程阻塞,最后形成死锁。

2.3.1 解决方式

使用自定义线程池,请求队列控制数量,等待加上超时时间,使用拒绝策略。

三、同步屏障CyclicBarrier

CyclicBarrier的字面意思是可循环使用(Cyclic)的屏障(Barrier)。它要做的事情是,让所有的线程都到达屏障(同步点)的时候,屏障才会打开,所有的线程才会往下执行。

3.1 应用场景
  • 玩排位的时候,会等待10个游戏玩家都准备好了之后才会开始游戏。
  • 朋友聚会的时候,会等待所有人都到齐了才会开始吃饭。
  • 闯关游戏,所有玩家都完成当前关卡后再一起去下一关。
3.2 排位代码 3.2.1 主要的方法

await():将当前线程阻塞,等到所有的线程都到达屏障后一起执行。

reset():将屏障重置为初始状态之后就可以复用。

isBroken(): 方法检测Barrier是否被破坏。

public static void main(String[] args) throws BrokenBarrierException, InterruptedException {
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(5, 10, 10, TimeUnit.MINUTES, new ArrayBlockingQueue<>(5));
        CyclicBarrier barrier = new CyclicBarrier(5);
        for (int i = 0; i < 5; i++) {
            threadPoolExecutor.execute(()->{
                try {
                    Thread.sleep(Math.round(1000));
                    System.out.println(Thread.currentThread().getName() + ": 玩家准备完成。");
                    barrier.await();
                } catch (InterruptedException | BrokenBarrierException e) {
                    e.printStackTrace();
                }
            });
        }
        barrier.await();
        System.out.println("玩家全部准备完成!开始游戏。");
        threadPoolExecutor.shutdown();
    }


pool-1-thread-3: 玩家准备完成。
pool-1-thread-1: 玩家准备完成。
pool-1-thread-2: 玩家准备完成。
pool-1-thread-4: 玩家准备完成。
pool-1-thread-5: 玩家准备完成。
玩家全部准备完成!开始游戏。
四、CountDownLatch与CyclicBarrier的区别
  • CountDownLatch的计数器只能使用一次。而CyclicBarrier的计数器可以使用reset() 方法重置,强调循环。
  • CyclicBarrier能处理更为复杂的业务场景,比如计算发生错误,可以结束阻塞,重置计数器,重新执行程序。
  • CyclicBarrier还提供getNumberWaiting(可以获得CyclicBarrier阻塞的线程数量)、isBroken(用来知道阻塞的线程是否被中断)等方法。
  • CountDownLatch会阻塞主线程,CyclicBarrier不会阻塞主线程,只会阻塞子线程。
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/887733.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号