Spring异步机制:@Async
概述
当一个方法标注@Async注解时,该方法的调用将异步发生;这意味着调用者将在调用后立即返回,方法的实际执行将发生在提交给Spring TaskExecutor的任务中。
示例
示例1
使用@EnableAsync注解启用异步机制
@EnableAsync @Configuration public class AsyncConfig { }
@Service public class AsyncJob { @Async public void asyncMethodWithVoidReturnType() { System.out.println("Execute method asynchronously: start." + Thread.currentThread().getName()); try { Thread.sleep(10 * 1000L); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Execute method asynchronously: end." + Thread.currentThread().getName()); } }
@RestController @RequestMapping("/home") public class HomeController { @Autowired private AsyncJob asyncJob; @GetMapping("/user-info") public String queryUserName() { asyncJob.asyncMethodWithVoidReturnType(); return "test - user"; } }
运行结果
Postman
日志
从上述日志中线程的名称可以知道,本示例中异步执行方法所用的线程池为Spring boot默认配置的线程池(TaskExecutionAutoConfiguration)
示例2
自定义线程池
@Configuration public class ThreadPoolConfig { @Bean public ThreadPoolTaskExecutor taskExecutor() { ThreadPoolTaskExecutor poolExecutor = new ThreadPoolTaskExecutor(); // 核心线程数 poolExecutor.setCorePoolSize(1); // 最大线程数 poolExecutor.setMaxPoolSize(3); // 队列大小 poolExecutor.setQueueCapacity(5); // 线程最大空闲时间 poolExecutor.setKeepAliveSeconds(60); // 拒绝策略 poolExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy()); // 线程名称前缀 poolExecutor.setThreadNamePrefix("sendMessage-"); return poolExecutor; } }
@Service public class AsyncJob { @Async("taskExecutor") public void asyncMethodWithVoidReturnType() { System.out.println("Execute method asynchronously: start." + Thread.currentThread().getName()); try { Thread.sleep(10 * 1000L); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Execute method asynchronously: end." + Thread.currentThread().getName()); } }
public class AsyncJobTest extends BaseTest { @Autowired private AsyncJob asyncJob; @Test void check_async() { System.out.println("check_async. " + Thread.currentThread().getName()); asyncJob.asyncMethodWithVoidReturnType(); try { Thread.sleep(30 * 1000L); } catch (InterruptedException e) { e.printStackTrace(); } } }
运行结果
揭秘 - 线程池
(1)通过@Async注解指定线程池的秘密
(2)使用Spring boot默认线程池(即:taskExecutor) 或者 SimpleAsyncTaskExecutor 的秘密
补充 - Spring Boot默认提供了名称为taskExecutor的线程池,所以我们在程序中不应该再自定义名称为taskExecutor的线程池
此处示例是通过@Autowire注解的方式注入线程池,区别于前面异步注解中指明线程池的方式
Future
如果@Async方法需要返回运行结果,可声明方法返回值为Future类型:
A、可以声明为常规的Java .util.concurrent. future类型
B、可以声明为Spring的org.springframework.util.concurrent.ListenableFuture类型
C、从Spring 4.2开始也可以声明为Java中的CompletableFuture
@Service public class AsyncJob { @Async public CompletableFuture<Integer> getEmployeeCount() { int count = 0; // ... return CompletableFuture.completedFuture(count); } }
扩展阅读
How To Do @Async in Spring | Baeldung