CompletableFuture使用自定义线程池实现多任务结果聚合返回
为什么要使用自定义线程池?
默认线程池缺点
1、CompletableFuture
默认使用的线程池是 ForkJoinPool.commonPool()
,commonPool是当前 JVM(进程) 上的所有 CompletableFuture、并行 Stream 共享的,commonPool 的目标场景是非阻塞的 CPU 密集型任务,其线程数默认为 CPU 数量减1,所以对于我们用java常做的IO密集型任务,默认线程池是远远不够使用的
2、CompletableFuture
是否使用默认线程池的依据,和机器的CPU核心数有关。当CPU核心数-1>1时,才会使用默认的线程池,否则将会为每个CompletableFuture的任务创建一个新线程去执行。
也就是说,CompletableFuture的默认线程池,只有在双核以上的机器内才会使用。在双核及以下的机器中,会为每个任务创建一个新线程,等于没有使用线程池,且有资源耗尽的风险。
因此建议,在使用CompletableFuture时,务必要自定义线程池。
创建自定义线程池
@Configuration
public class ThreadPoolConfig {
//参数初始化
private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
//核心线程数量大小
private static final int corePoolSize = Math.max(2, Math.min(CPU_COUNT-1,4));
//线程池最大容纳线程数
private static final int maxPoolSize = CPU_COUNT * 2 + 1;
//阻塞队列
private static final int workQueue = 20;
//线程空闲后的存活时长
private static final int keepAliveTime = 30;
@Bean("asyncTaskExecutor")
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
//核心线程数
threadPoolTaskExecutor.setCorePoolSize(corePoolSize);
//最大线程数
threadPoolTaskExecutor.setMaxPoolSize(maxPoolSize);
//等待队列
threadPoolTaskExecutor.setQueueCapacity(workQueue);
//线程前缀
threadPoolTaskExecutor.setThreadNamePrefix("asyncTaskExecutor-");
//线程池维护线程所允许的空闲时间,单位为秒
threadPoolTaskExecutor.setKeepAliveSeconds(keepAliveTime);
// 线程池对拒绝任务(无线程可用)的处理策略
threadPoolTaskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
threadPoolTaskExecutor.initialize();
return threadPoolTaskExecutor;
}
}
var code = “44408f2e-720a-4910-9560-8379269da088”
在CompletableFuture中指定自定义线程池
@RestController
@RequestMapping("/task")
public class CompletableTaskController {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@Autowired
@Qualifier("asyncTaskExecutor")
private Executor asyncTaskExecutor;
@RequestMapping("testOrderTask")
public String testOrderTask(){
List<CompletableFuture<List<Integer>>> futureList = Lists.newArrayList();
// 任务1,计算3秒
CompletableFuture<List<Integer>> task1 = CompletableFuture.supplyAsync(() -> {
sleepSeconds(3L);
return Lists.newArrayList(1,2,3);
}, asyncTaskExecutor);
futureList.add(task1);
// 任务2,计算2秒,得答案5
CompletableFuture<List<Integer>> task2 = CompletableFuture.supplyAsync(() -> {
sleepSeconds(1L);
return Lists.newArrayList(4,5,6);
}, asyncTaskExecutor);
futureList.add(task2);
// 任务3,计算3秒,得答案5
CompletableFuture<List<Integer>> task3 = CompletableFuture.supplyAsync(() -> {
sleepSeconds(2L);
return Lists.newArrayList(7,8,9);
}, asyncTaskExecutor);
futureList.add(task3);
// 写法1
List<Integer> newList = futureList.stream().map(CompletableFuture::join).flatMap(List::stream).collect(Collectors.toList());
return JSON.toJSONString(newList);
}
private void sleepSeconds(long seconds) {
try {
Thread.sleep(seconds * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
测试
运行以上程序,会 有以下输出:
1,2,3,4,5,6,7,8,9