问题
有些时候,我们需要等所有线程执行完后,再执行后面的业务代码。解决方案可以有:
方案一:使用信号量 CountDownLatch
1.自定义线程池配置(Bean定义)
@Bean("markUserThread")
public ThreadPoolTaskExecutor executeMarkUserThread() {
ThreadPoolTaskExecutor poolExecutor = new ThreadPoolTaskExecutor();
poolExecutor.setCorePoolSize(5);
poolExecutor.setMaxPoolSize(60);
poolExecutor.setQueueCapacity(5000);
poolExecutor.setKeepAliveSeconds(10);
poolExecutor.setThreadNamePrefix("markUserThread-");
poolExecutor.setWaitForTasksToCompleteOnShutdown(true);
poolExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
poolExecutor.setAwaitTerminationSeconds(60);
poolExecutor.initialize();
return poolExecutor;
}
定义了一个核心线程数为5,最大线程数60的线程池。
2.线程池Bean注入
@Resource(name = "markUserThread")
private ThreadPoolTaskExecutor poolTaskExecutor;
3.线程池使用
// 对大集合(任务)进行切分
List<List<Object>> partitionList = Lists.partition(dataList, 100);
// 计算要运行的线程数
int threadNum = partitionList.size();
threadNum = Math.min(threadNum, 60);
// 初始化信号量
CountDownLatch latch = new CountDownLatch(threadNum);
partitionList.forEach(list -> {
poolTaskExecutor.submit(() ->
// 业务代码
);
// 信号量减1
latch.countDown();
});
try {
// 等待所有线程执行完成
latch.await();
log.info("usePoolTaskExecutorMarkUserTag end->{}", threadNum);
} catch (Exception e) {
throw e;
}
方案二:使用CompletableFuture
1.自定义线程池(同上)
2.注解@Async引入
@Async("markUserThread")
public CompletableFuture<String> dataListHandler(List<Integer> dataList) {
dataList.forEach(rs -> {
log.info("dataListHandler->{}", rs);
});
return CompletableFuture.completedFuture("success");
}
3.业务调用(⚠️必须在其他类文件中调用加了Async注解的方法)
// 定义Future对象
List<CompletableFuture<?>> futures = Lists.newArrayList();
// 对大集合(任务)进行切分
List<List<Integer>> result = Lists.partition(elements, 100);
result.forEach(res -> {
futures.add(asyncCommand.dataListHandler(res));
});
// 等待所有线程执行完成
CompletableFuture.allOf(futures.toArray(new CompletableFuture<?>[0])).join();
log.info("task over!!!");