背景
什么是 CompletableFuture??
给大家找到了介绍它的一篇文章,我觉得还写的挺好的:
https://blog.youkuaiyun.com/u011837804/article/details/129975559
正文
我们在 CompletableFuture 的基础上对它进行第二次封装,让我们可以方便的提交我们想执行的异步任务,而且能保证我们的任务能同时被执行
import cn.hutool.core.collection.CollUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.google.common.collect.Lists;
import lombok.SneakyThrows;
import org.apache.commons.lang3.ArrayUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
public class FutureUtilOpt {
private final List<CompletableFuture<Void>> futures = Lists.newArrayList();
/**
* 同时异步执行多个方法
*
* @param actions Runnable方法,建议使用lambda表达式更清晰
*/
@SneakyThrows
public static void runActions(Executor executor, Runnable... actions) {
if (ArrayUtils.isEmpty(actions)) {
return;
}
FutureUtilOpt util = new FutureUtilOpt();
for (Runnable action : actions) {
util.add(executor, action);
}
util.execute();
}
/**
* 同时异步执行多个方法
*
* @param actions Runnable方法,建议使用lambda表达式更清晰
*/
@SneakyThrows
public static void runActions(Runnable... actions) {
runActions(null, actions);
}
/**
* futures添加action
*/
private void add(Executor executor, Runnable action) {
ServletRequestAttributes sra = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
RequestContextHolder.setRequestAttributes(sra, true);
if (null == executor) {
executor = SpringUtil.getBean("你项目的线程池对象名称");
}
if (null == executor) {
//未配置线程池,则使用默认线程池 ForkJoinPool
futures.add(CompletableFuture.runAsync(action));
} else {
futures.add(CompletableFuture.runAsync(action, executor));
}
}
/**
* 执行所有future
*/
private void execute() throws ExecutionException, InterruptedException {
if (CollUtil.isEmpty(futures)) {
return;
}
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).get();
}
}
能保证提交的任务同时执行,都在 .allOf() 这个方法。
要保证你的Spring容器里面有你要的 线程池对象:
你需要这样一个配置类:
@Configuration
@EnableAsync
@Order(Integer.MIN_VALUE)
@Slf4j
public class ThreadPoolTaskConfig {
@Bean("testExecutor")
public Executor optTtlTaskExecutor() {
log.info("testExecutor initialize");
ThreadPoolTaskExecutor executor = buildThreadPoolTaskExecutor("async-Service-");
// 初始化
executor.initialize();
//TtlExecutors: com.alibaba.ttl.threadpool
return TtlExecutors.getTtlExecutor(executor);
}
/**
* 构建执行器
*
* @param threadNamePrefix
* @return
*/
private ThreadPoolTaskExecutor buildThreadPoolTaskExecutor(String threadNamePrefix) {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(CORE_POOL_SIZE);
executor.setMaxPoolSize(MAX_POOL_SIZE);
executor.setQueueCapacity(QUEUE_CAPACITY);
executor.setKeepAliveSeconds(KEEP_ALIVE_TIME);
executor.setThreadNamePrefix(threadNamePrefix);
// 线程池对拒绝任务的处理策略
// CallerRunsPolicy:由调用线程(提交任务的线程)处理该任务
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
return executor;
}
}
实验一下:
@GetMapping("/test1")
public void test(){
FutureUtilOpt.runActions(
() -> System.out.println("要执行的任务1"),
() -> System.out.println("要执行的任务2"),
() -> System.out.println("要执行的任务3")
);
}
运行结果:
第一次执行:
要执行的任务2
要执行的任务3
要执行的任务1
第二次执行:
要执行的任务1
要执行的任务2
要执行的任务3
嗯,非常好用