SpringBoot @Async 异步方法内部再调用异步方法

异步方法

背景

系统有一个接口,业务比较复杂,执行耗时会很长时间,但是前端页面需要很快返回结果。
使用@Async注解,将执行耗时很长的逻辑异步处理。
不过这个异步处理逻辑里面又需要依次去执行一系列执行耗时很长的逻辑。 最后需要对这些耗时较长任务的执行结果做一些处理。

伪代码:
@Async("xxxx")
public void xxxx(){
	//做一些增删改查
	doSomethings()
	for(xxx xx : xxx{
		//这个操作很耗时间,且for次数比较多,如果依次执行,会很耗时间,所以就想将里面的任务也并行。
		xx.doSomeThing(); 
	}
	//需要根据for循环中每一个任务的执行结果去做一些操作
	doSomeThings();
}

所以

  1. 第一层异步:将整个耗时较长的逻辑写到一个 @Async注解下的方法里
  2. 第二层异步:将里面需要依次执行的任务也扔到线程池里面去,让他们同时执行(需要保证线程池核心大小 > 需要执行任务的次数
  3. 因为第一层异步还需要用到第二层异步的一些结果,所以利用CountDownLatch来做 线程协作

代码

  • 线程池配置
@Configuration
@EnableAsync
public class ExecutorConfig {

    @Bean("taskExecutor")
    public Executor taskExecutor(){
        ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
        taskExecutor.setCorePoolSize(20);
        taskExecutor.setMaxPoolSize(50);
        taskExecutor.setQueueCapacity(200);
        taskExecutor.setKeepAliveSeconds(60);
        taskExecutor.setThreadNamePrefix("taskExecutor--test-");
        taskExecutor.setWaitForTasksToCompleteOnShutdown(true);
        taskExecutor.setAwaitTerminationSeconds(60);
        return taskExecutor;
    }
}
  • 主方法
@Component
public class CountDownLatchTestJob {

    private final static Logger log = LoggerFactory.getLogger(CountDownLatchTestJob.class);

    @Autowired
    private InsideJob insideJob;

    @Async("taskExecutor")
    public void mainMethod() throws InterruptedException {
        long begin = System.currentTimeMillis();
        log.info("start main method");
        log.info("main method thread: {}", Thread.currentThread().getName());
        CountDownLatch count = new CountDownLatch(10);
        for(int i = 0; i < 10; i++){
            insideJob.insideCdlMethod(count);
        }
        count.await();
        log.info("main method end");
        long end = System.currentTimeMillis();
        log.info("task cost time:{}", end - begin);
    }
}
  • 内部方法
@Component
public class InsideJob {

    private final static Logger log = LoggerFactory.getLogger(InsideJob.class);

    @Async("taskExecutor")
    public void  insideCdlMethod(CountDownLatch count){
        log.info("start inside method " + count.getCount());
        try {
            Thread.sleep(1000);
            log.info("inside method thread: {}", Thread.currentThread().getName());
        } catch (InterruptedException e) {
            log.warn(String.format("xxxxx %s", "sdw"), e);
        }
        count.countDown();
        log.info("inside method end " + count.getCount());
    }
}

主方法将CountDownLatch作为参数传入内部异步方法,然后主方法一直等着内部异步方法执行完成。
才能继续下面的处理逻辑。

提示

这里的主异步方法和内部异步方法不能写在一个类里面,不然mainMethod 调用 insideCdlMethod的时候,会因为没有生成代理,而没有办法启用新的线程。

  • 10
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值