对 CompletableFuture的二次封装,让它同时调用多个异步方法

背景

什么是 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

嗯,非常好用

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值