您现在的位置是:亿华云 > IT科技

详解SpringBoot中的异步调用@Async

亿华云2025-10-03 02:07:54【IT科技】2人已围观

简介如何开启异步调用在SpringBoot中,只需要给方法加上@Async注解,就能将同步方法变为异步调用。首先在启动类上添加@EnableAsync,即开启异步调用。/***@authorqcy*/@S

如何开启异步调用

在SpringBoot中,详解只需要给方法加上@Async注解,异步就能将同步方法变为异步调用。调用

首先在启动类上添加@EnableAsync,详解即开启异步调用。异步

/**  * @author qcy  */ @SpringBootApplication @EnableAsync public class AsyncApplication {      public static void main(String[] args) {          SpringApplication.run(AsyncApplication.class,调用 args);     } } 

在需要异步调用的方法上加上@Async注解

package com.yang.async; import lombok.extern.slf4j.Slf4j; import org.springframework.scheduling.annotation.Async; import org.springframework.scheduling.annotation.AsyncResult; import org.springframework.stereotype.Component; import java.util.concurrent.Future; import java.util.concurrent.FutureTask; /**  * @author qcy  * @create 2020/09/09 14:01:35  */ @Slf4j @Component public class Task {      @Async     public void method1() {          log.info("method1开始,执行线程为" + Thread.currentThread().getName());         try {              Thread.sleep(2000);         } catch (InterruptedException e) {              e.printStackTrace();         }         log.info("method1结束");     }     @Async     public void method2() {          log.info("method2开始,执行线程为" + Thread.currentThread().getName());         try {              Thread.sleep(3000);         } catch (InterruptedException e) {              e.printStackTrace();         }         log.info("method2结束");     } } 

 测试一下:

@SpringBootTest @Slf4j public class AsyncApplicationTests {      @Autowired     Task task;     @Test     public void testAsyncWithVoidReturn() throws InterruptedException {          log.info("main线程开始");         task.method1();         task.method2();         //确保两个异步调用执行完成         Thread.sleep(6000);         log.info("main线程结束");     } } 

 输出如下:

可以看得出,SpringBoot创建了一个名为applicationTaskExecutor的详解线程池,使用这里面的异步线程来执行异步调用。

这里值得注意的调用是,不要在一个类中调用@Async标注的详解方法,否则不会起到异步调用的异步作用,至于为什么会产生这样的调用问题,网站模板需要深入到源码中一探究竟,详解会另开篇幅。异步

既然默认使用的调用是SpringBoot自己创建的applicationTaskExecutor,那如何自己去定义一个线程池呢?

自定义线程池

我们需要手动创建一个名为asynTaskExecutord的Bean

package com.yang.async; import lombok.extern.slf4j.Slf4j; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.task.AsyncTaskExecutor; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import java.util.concurrent.ThreadPoolExecutor; /**  * @author qcy  * @create 2020/09/09 15:31:07  */ @Slf4j @Configuration public class AsyncConfig {      @Bean     public AsyncTaskExecutor asyncTaskExecutor() {          ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();         executor.setCorePoolSize(8);         executor.setMaxPoolSize(16);         executor.setQueueCapacity(50);         executor.setAllowCoreThreadTimeOut(true);         executor.setKeepAliveSeconds(10);         executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());         executor.setThreadNamePrefix("async-thread-pool-thread");         return executor;     } } 

 对以上参数不了解的同学,可以参考我的这篇文章说说线程池

其他类不需要变动,直接运行刚才的testAsyncWithVoidReturn()方法,输出:

看得出来,现在是我们自定义的线程池

如果关心异步调用的返回值,又怎么处理?

获取异步调用的服务器托管返回结果

获取异步调用的结果,需要利用Future机制,可以参考我的另外一篇文章谈谈Runnable、Future、Callable、FutureTask之间的关系

为Task类增加以下两个方法:

@Async   public Future<String> method3() {        log.info("method3开始,执行线程为" + Thread.currentThread().getName());       try {            Thread.sleep(1000);       } catch (InterruptedException e) {            e.printStackTrace();       }       log.info("method3结束");       return new AsyncResult<>("method3");   }   @Async   public Future<String> method4() {        log.info("method4开始,执行线程为" + Thread.currentThread().getName());       try {            Thread.sleep(3000);       } catch (InterruptedException e) {            e.printStackTrace();       }       log.info("method4结束");       return new AsyncResult<>("method4");   } 

 测试类:

@Test   public void testAsyncWithStringReturn() throws InterruptedException, ExecutionException {        log.info("main线程开始");       Future<String> method3Result = task.method3();       Future<String> method4Result = task.method4();       //get方法为阻塞获取       log.info("method3执行的返回结果:{ }", method3Result.get());       log.info("method4执行的返回结果:{ }", method4Result.get());       log.info("main线程结束");   } 

 输出:

如图,在主线程结束前,获取到了异步调用的结果。且在两个异步调用都结束的情况下,继续执行主线程。

很赞哦!(997)