一、创建线程池
@Configuration
public class ThreadPoolConfig {
private static final Integer THREAD_CORE_POOL_SIZE = Runtime.getRuntime().availableProcessors() * 5;
private static final Integer THREAD_MAX_POOL_SIZE = Runtime.getRuntime().availableProcessors() * 20;
private static final Integer THREAD_KEEP_ALIVE_TIME = 100;
private static final Integer THREAD_QUEUE_CAPACITY = 100;
/**
* 以ArrayBlockingQueue存储线程池中元素
* <p>
* 该线程池已处理过MDC
*
* @return
*/
@Bean("poolWithArray")
public ThreadPoolExecutor getThreadPoolWithArray() {
ThreadPoolExecutor executor = new ThreadPoolExecutor(
THREAD_CORE_POOL_SIZE,
THREAD_MAX_POOL_SIZE,
THREAD_KEEP_ALIVE_TIME,
TimeUnit.SECONDS,
new ArrayBlockingQueue<>(THREAD_QUEUE_CAPACITY),
new MDCThreadFactory(),
new ThreadPoolExecutor.CallerRunsPolicy()
);
return executor;
}
/**
* 以LinkedBlockingQueue存储线程池中元素
* <p>
* 该线程池已处理过MDC
*
* @return
*/
@Bean("poolWithLinked")
public ThreadPoolExecutor getThreadPoolWithLinked() {
ThreadPoolExecutor executor = new ThreadPoolExecutor(
THREAD_CORE_POOL_SIZE,
THREAD_MAX_POOL_SIZE,
THREAD_KEEP_ALIVE_TIME,
TimeUnit.SECONDS,
new LinkedBlockingQueue<>(THREAD_QUEUE_CAPACITY),
new MDCThreadFactory(),
new ThreadPoolExecutor.CallerRunsPolicy()
);
return executor;
}
@Bean("mdcThreadFactory")
public ThreadFactory getThreadFactory() {
return new MDCThreadFactory();
}
/**
* 重写ThreadFactory,获取外部MDC,方便日志追踪
*/
private class MDCThreadFactory implements ThreadFactory {
@Override
public Thread newThread(Runnable r) {
MDC.put("key", "value");
Map<String, String> copyOfContextMap = MDC.getCopyOfContextMap();
Thread thread = new Thread() {
@Override
public void run() {
MDC.setContextMap(copyOfContextMap);
r.run();
}
};
return thread;
}
}
}
二、循环获取CompletableFuture,阻塞并获取返回值
//多线程组装计划信息返回值
List<CompletableFuture<OperationPlanListVO>> completableFutureList = new ArrayList<>();
for (ZhywOperationPlanEntity zhywOperationPlanEntity : zhywOperationPlanEntityList) {
CompletableFuture<OperationPlanListVO> completableFuture = CompletableFuture.supplyAsync(() -> {
OperationPlanListVO operationPlanListVO = OperationPlanListVO.builder()
.planId(zhywOperationPlanEntity.getId())
.planEndTime(zhywOperationPlanEntity.getPlanEndTime())
.planStartTime(zhywOperationPlanEntity.getPlanStartTime())
.endBusinessId(zhywOperationPlanEntity.getBusinessId())
.endBusinessName(informationComparison.get(zhywOperationPlanEntity.getBusinessId()))
.executeFrequencyList(StringUtils.isNotBlank(zhywOperationPlanEntity.getExecutionFrequency()) ? JSON.parseArray(zhywOperationPlanEntity.getExecutionFrequency(), String.class) : new ArrayList<>())
.build();
//获取节点从属的结构名称
String dependenceName = getDependenceName(informationComparison, zhywOperationPlanEntity.getSubordinationId());
operationPlanListVO.setDependenceBusinessName(dependenceName);
return operationPlanListVO;
}, threadPoolExecutor);
completableFutureList.add(completableFuture);
}
CompletableFuture<OperationPlanListVO>[] completableFutures = new CompletableFuture[completableFutureList.size()];
completableFutureList.toArray(completableFutures);
List<OperationPlanListVO> operationPlanListVOList = new ArrayList<>();
try {
CompletableFuture.allOf(completableFutures).get();
for (CompletableFuture<OperationPlanListVO> completableFuture : completableFutureList) {
operationPlanListVOList.add(completableFuture.get());
}
} catch (Exception e) {
log.error("多线程构建计划信息列表失败,查询信息为:{},异常原因:{}", operationPlanListDTO, e);
}
注意:这里是通过多线程,异步执行,同步阻塞后,统一获取线程得返回值。如果不需要收集返回值,则使用
CompletableFuture.runAsync()
三、如果需要异步执行完再执行其他操作,可使用如下方式:
CompletableFuture.runAsync(() -> {
//重置全量业务信息对照集合
fullIdNameMap.clear();
Map<Long, String> allInformationComparison = getAllInformationComparison();
if (!CollectionUtils.isEmpty(allInformationComparison)) {
fullIdNameMap.putAll(allInformationComparison);
}
//重置有效的业务信息对照集合
voidIdNameMap.clear();
Map<Long, String> validInformationComparison = getValidInformationComparison();
if (!CollectionUtils.isEmpty(validInformationComparison)) {
voidIdNameMap.putAll(validInformationComparison);
}
}, threadPoolExecutor).thenRun(() -> {
log.info("全量业务信息对照集合重置成功,详情:{},有效业务信息对照重置成功,详情:{}", fullIdNameMap, voidIdNameMap);
});