企业🤖AI智能体构建引擎,智能编排和调试,一键部署,支持私有化部署方案 广告
[TOC] # 1. 异步方法内依然是同步的 异步方法的方法内依然是同步的,方法外才是异步的。如下示例。 **1. 异步方法** ```java @Slf4j @Service public class AsyncService { @Async public void asyncHandle1() { String name = "zhangsan"; log.info("[asyncHandle1|name1]: {}", name); try { Thread.sleep(5000); name = "lisi"; } catch (InterruptedException e) { e.printStackTrace(); } log.info("[asyncHandle1|name2]: {}", name); } } ``` **2. 其它类中调用异步方法** ```java @Slf4j @RestController @RequiredArgsConstructor public class AsyncController { final AsyncService asyncService; @GetMapping("/v1/asyncHandle1") public void asyncHandle1() { log.info("[asyncHandle1|start]"); //调用异步方法 asyncService.asyncHandle1(); log.info("[asyncHandle1|end]"); } } ``` ``` ///日志打印顺序如下,异步方法的方法内依然是同步的,方法外才是异步的 2023-06-02 17:34:10 ...: [asyncHandle1|start] 2023-06-02 17:34:10 ...: [asyncHandle1|end] 2023-06-02 17:34:10 ...: [asyncHandle1|name1]: zhangsan -- 等待 5s 后输出 lisi,而不是zhangsan 2023-06-02 17:34:15 ...: [asyncHandle1|name2]: lisi ``` <br/> # 2. 引起@Async失效的情况 转载自:https://zhuanlan.zhihu.com/p/462544527 **** * 异步方法使用static修饰。 * 异步类没有使用@Component注解(或其他注解)导致spring无法扫描到异步类。 * 异步方法被同类的方法(异步/同步)调用会失效。 * 类中需要使用@Autowired或@Resource等注解自动注入,不能自己手动new对象。 * 如果使用SpringBoot框架必须在启动类中增加@EnableAsync注解。 * 异步方法将Future作为返回值。 <br/> # 3. @Async的原理简述 转载自:https://blog.csdn.net/qq_44750696/article/details/123960134 **** @Async 的原理是通过 Spring AOP 动态代理的方式来实现的。 <br/> Spring 容器启动初始化 bean 时,判断类中是否使用了 @Async 注解,如果使用了则为其创建切入点和切入点处理器,根据切入点创建代理。 <br/> 在线程调用 @Async 注解标注的方法时,会调用代理,执行切入点处理器`invoke`方法,将方法的执行提交给线程池中的另外一个线程来处理,从而实现了异步执行。 <br/> 所以,需要注意的一个错误用法是,如果 A 方法(不论是同步还是异步)调用它同类中标注 @Async 的 B 方法,是不会异步执行的,因为从 A 方法进入调用的都是该类对象本身,不会进入代理类。因此,<mark>相同类中的方法调用带 @Async 的方法是无法异步的,这种情况仍然是同步</mark>。 <br/> # 4. 异步方法返回值 可以将 Future 作为异步方法的返回值,但当调用`Future.get`时主线程就会被阻塞,这时异步方法就不再是异步执行了。 **1. 异步方法返回 Future** ```java @Slf4j @Service public class AsyncService { @Async public Future<String> asyncHandle2() { try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } log.info("[asyncHandle2]"); return CompletableFuture.completedFuture("张三"); } } ``` <br/> **2. 其它类中调用异步方法** ```java @Slf4j @RestController @RequiredArgsConstructor public class AsyncController { final AsyncService asyncService; @GetMapping("/v1/asyncHandle2") public void asyncHandle2() throws ExecutionException, InterruptedException { log.info("[asyncHandle2|start]"); //调用异步方法 Future<String> result = asyncService.asyncHandle2(); //如果调用 get,则 asyncService.asyncHandle2()不是异步执行了 log.info("[asyncHandle2|name]: {}", result.get()); } } ``` 日志打印顺序如下,说明异步没有执行。 ``` ///调用 get 日志打印顺序如下,说明异步没有执行 2023-06-02 18:20:49 ...: [asyncHandle2|start] 2023-06-02 18:20:54 ...: [asyncHandle2] -- 等待 5s 后输出 2023-06-02 18:20:54 ...: [asyncHandle2|name]: 张三 ///没有调用 get 日志打印顺序如下,说明异步执行了 2023-06-02T18:23:44 ...: [asyncHandle2|start] 2023-06-02T18:23:44 ...: [asyncHandle2|name]: -- 等待 5s 后输出 2023-06-02T18:23:49 ...: [asyncHandle2] ``` >[info]异步方法只能返回 Future,或 void。