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完成-当前阶段的汇总任务...