看明白Java多线程:CountDownLatch和CyclicBarrier

1、CountDownLatch

主要用于:

一个主线程等待多个子线程都执行完成后,才能继续执行的场景
适用于框架启动前,进行多项初始化工作等场景:多项初始化工作都完成后,才能开始启动框架处理。
或者用于统计多个线程是否都已执行完成:kafka消费者多线程执行消费,多个子线程并行执行,只有当子线程都执行完成后,才能提交offset

package com.autoee.demo.javabase.mutiThread.CountDownLatch;

import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.RandomUtil;
import lombok.SneakyThrows;

import java.util.concurrent.CountDownLatch;

/**
 * Title: <br>
 * Desc: <br>
 * Date: 2022-8-26 <br>
 * @author Double
 * @version 1.0.0
 */
public class CountDownLatchTest1 {

    // CountDownLatch主要用来解决:
    // 一个主线程等待多个子线程都执行完成后,才能继续执行的场景
    // 适用于框架启动前,进行多项初始化工作等场景:多项初始化工作都完成后,才能开始启动框架处理。
    // 或者用于统计多个线程是否都已执行完成:kafka消费者多线程执行消费,多个子线程并行执行,只有当子线程都执行完成后,才能提交offset
    public static void main(String[] args) throws InterruptedException {
        // CountDownLatch中的个数要和实际执行的子线程数一致,否则执行过程就混乱了。
        int threadCount = 5;
        CountDownLatch tCountDownLatch = new CountDownLatch(threadCount);

        for (int i = 0; i < threadCount; i++) {
            new Thread("thread" + i) {
                @Override
                public void run() {
                    String name = Thread.currentThread().getName();
                    ThreadUtil.sleep(RandomUtil.randomInt(100) * 100);
                    System.out.println("子线程" + name + "执行完成。");

                    // 当前子线程执行完成,减1
                    tCountDownLatch.countDown();
                }
            }.start();

        }

        // 阻塞等待上面的多个线程都执行完成
        tCountDownLatch.await();

        System.out.println("上面的子线程都已执行完成,主线程开始后续处理。。。");

    }

}

执行结果

子线程thread3执行完成。
子线程thread0执行完成。
子线程thread2执行完成。
子线程thread4执行完成。
子线程thread1执行完成。
上面的子线程都已执行完成,主线程开始后续处理。。。

2、CyclicBarrier

主要用于

多个线程并行执行多个阶段的任务,第1阶段任务所有子线程都执行完成后,所有子线程再开始第2阶段的任务,
第2阶段任务所有子线程都执行完成后,再进入下一阶段任务...
每个阶段所有子线程都执行完成后,主线程还可以执行一次该阶段的汇总任务。
package com.autoee.demo.javabase.mutiThread.CyclicBarrier;

import cn.hutool.core.thread.ThreadUtil;
import lombok.SneakyThrows;

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.CyclicBarrier;

/**
 * Title: <br>
 * Desc: <br>
 * Date: 2022-8-26 <br>
 * @author Double
 * @version 1.0.0
 */
public class CyclicBarrierTest1 {

    // CyclicBarrier主要用于:
    // 多个线程并行执行多个阶段的任务,第1阶段任务所有子线程都执行完成后,所有子线程再开始第2阶段的任务,
    // 第2阶段任务所有子线程都执行完成后,再进入下一阶段任务...
    // 每个阶段所有子线程都执行完成后,主线程还可以执行一次该阶段的汇总任务。
    public static void main(String[] args) {

        // 存放每阶段所有子线程的执行结果
        ConcurrentHashMap<String, String> resultMap = new ConcurrentHashMap<String, String>();

        // CyclicBarrier中的parties要和实际执行的子线程数一致,否则执行过程就混乱了。
        int threadCount = 3;

        // 创建CyclicBarrier,并定义每阶段执行完成后的汇总任务
        CyclicBarrier tCyclicBarrier = new CyclicBarrier(threadCount, new Runnable() {
            @Override
            public void run() {
                long id = Thread.currentThread().getId();
                System.out.println("【开始】-每个阶段任务所有子线程都执行完成后-汇总线程" + id + "开始-当前阶段的汇总任务...");
                resultMap.forEach((k, v) -> {
                    System.out.println("----------[获取]-" + v);
                });
                System.out.println("【完成】-每个阶段任务所有子线程都执行完成后-汇总线程" + id + "完成-当前阶段的汇总任务...");
            }
        });

        // 创建多个子线程,并发执行每个阶段的任务
        for (int i = 0; i < threadCount; i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    long id = Thread.currentThread().getId();
                    String name = Thread.currentThread().getName();
                    System.out.println("[开始]-" + name + "-第1阶段任务...");
                    ThreadUtil.sleep(1000 + id);
                    System.out.println("[完成]-" + name + "-第1阶段任务...");

                    // 将子线程当前阶段的执行结果放入resultMap,key为线程名称
                    resultMap.put(name, "子线程-" + name + "-第1阶段-sleep时间=" + (1000 + id));
                    try {
                        // 所有子线程等待其他子线程完成第一阶段任务,等都完成后,再进入下一阶段
                        tCyclicBarrier.await();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }

                    System.out.println("[开始]-" + name + "-第2阶段任务...");
                    ThreadUtil.sleep(1000 + id);
                    System.out.println("[完成]-" + name + "-第2阶段任务...");

                    // 将子线程当前阶段的执行结果放入resultMap,key为线程名称,覆盖上一阶段的执行结果
                    resultMap.put(name, "子线程-" + name + "-第2阶段-sleep时间=" + (1000 + id));
                    try {
                        // 所有子线程等待其他子线程完成第一阶段任务,等都完成后,再进入下一阶段
                        tCyclicBarrier.await();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }

                }
            }, "线程" + (i + 1)).start();
        }

        System.out.println("上面的子线程不会阻塞当前主线程的执行");
    }
}

执行结果

上面的子线程不会阻塞当前主线程的执行
[开始]-线程3-第1阶段任务...
[开始]-线程2-第1阶段任务...
[开始]-线程1-第1阶段任务...
[完成]-线程1-第1阶段任务...
[完成]-线程2-第1阶段任务...
[完成]-线程3-第1阶段任务...
【开始】-每个阶段任务所有子线程都执行完成后-汇总线程14开始-当前阶段的汇总任务...
----------[获取]-子线程-线程2-第1阶段-sleep时间=1013
----------[获取]-子线程-线程3-第1阶段-sleep时间=1014
----------[获取]-子线程-线程1-第1阶段-sleep时间=1012
【完成】-每个阶段任务所有子线程都执行完成后-汇总线程14完成-当前阶段的汇总任务...
[开始]-线程3-第2阶段任务...
[开始]-线程1-第2阶段任务...
[开始]-线程2-第2阶段任务...
[完成]-线程1-第2阶段任务...
[完成]-线程2-第2阶段任务...
[完成]-线程3-第2阶段任务...
【开始】-每个阶段任务所有子线程都执行完成后-汇总线程14开始-当前阶段的汇总任务...
----------[获取]-子线程-线程2-第2阶段-sleep时间=1013
----------[获取]-子线程-线程3-第2阶段-sleep时间=1014
----------[获取]-子线程-线程1-第2阶段-sleep时间=1012
【完成】-每个阶段任务所有子线程都执行完成后-汇总线程14完成-当前阶段的汇总任务...

 如果对您有帮助,请我喝杯咖啡吧!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值