本文带你快速了解@Async注解的用法,包括异步方法无返回值、有返回值,最后总结了@Async注解失效的几个坑。
在 SpringBoot 应用中,经常会遇到在一个接口中,同时做事情1,事情2,事情3;
如果同步执行的话,则本次接口时间取决于事情1 2 3执行时间之和;
如果三件事同时执行,则本次接口时间取决于事情1 2 3执行时间最长的那个;
合理使用多线程,可以大大缩短接口时间。
那么在 SpringBoot 应用中如何优雅的使用多线程呢?
快速使用
SpringBoot应用中需要添加 @EnableAsync
注解,来开启异步调用,一般还会配置一个线程池,异步的方法交给特定的线程池完成,如下:
1 |
|
使用的方式非常简单,在需要异步的方法上加@Async
注解
1 |
|
1 | 4j |
访问:127.0.0.1:8080/open/something
,即可看到效果。
达到异步执行的效果了,并且使用到了咱们配置的线程池。
获取异步方法返回值
当异步方法有返回值时,如何获取异步方法执行的返回结果呢?
这时需要异步调用的方法带有返回值 CompletableFuture
。
CompletableFuture是对Future的增强,Future只能处理简单的异步任务,而CompletableFuture可以将多个异步任务进行复杂的组合。如下:
1 |
|
1 | 4j |
访问接口
1 | C:\Users\Administrator>curl -X GET "http://localhost:8200/open/somethings" -H "accept: */*" |
控制台上关键日志如下:
1 | 2021-12-29 17:27:42.238 INFO 5672 --- [ do-something-3] x.gits.boot.system.service.AsyncService : do something3: save log |
注意事项
@Async
注解会在以下几个场景失效,也就是说明明使用了@Async
注解,但就没有走多线程。
- 异步方法使用static关键词修饰;
- 异步类不是一个Spring容器的bean(一般使用注解
@Component
和@Service
,并且能被Spring扫描到); - SpringBoot应用中没有添加
@EnableAsync
注解; - 在同一个类中,一个方法调用另外一个有@Async注解的方法,注解不会生效。原因是@Async注解的方法,是在代理类中执行的。
需要注意的是: 异步方法使用注解@Async的返回值只能为void或者Future及其子类,当返回结果为其他类型时,方法还是会异步执行,但是返回值都是null,部分源码如下:
AsyncExecutionInterceptor#invoke
通过上边几个示例,@Async实际还是通过Future或CompletableFuture来异步执行的,Spring又封装了一下,让我们使用的更方便。