💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
[TOC] # 1. 异步方法内依然是同步的 异步方法的方法内依然是同步的,方法外才是异步的。如下示例。 **1. 异步方法** ```java @Slf4j @Service public class AsyncService { @Async public void async02() { String name = "zhangsan"; log.info("AsyncService -> async02 -> name001({})", name); try { Thread.sleep(5000); name = "wangwu"; log.info("AsyncService -> async02 -> name002({})", name); } catch (InterruptedException e) { e.printStackTrace(); } log.info("AsyncService -> async02 -> name003({})", name); } } ``` **2. 同步方法调用异步方法** ```java @Slf4j @RestController public class AsyncController { @Autowired AsyncService asyncService; @GetMapping("/sync02") public void sync02() { log.info("AsyncController -> sync02 -> 001"); //同步方法中调用异步方法 asyncService.async02(); log.info("AsyncController -> sync02 -> 002"); } } ``` 日志打印顺序如下。 ``` 2022-09-07 11:08:36 : AsyncController -> sync02 -> 001 2022-09-07 11:08:36 : AsyncController -> sync02 -> 002 2022-09-07 11:08:36 : AsyncService -> async02 -> name001(zhangsan) -- 等待5s输出下面内容 2022-09-07 11:08:41 : AsyncService -> async02 -> name002(wangwu) 2022-09-07 11:08:41 : AsyncService -> async02 -> name003(wangwu) ``` <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. 异步方法返回值 **1. 调用异步方法是获取不到该异步方法的返回值的** ```java // 异步方法 @Async public String async03() { String name = "zhangsan"; log.info("AsyncService -> async03 -> name001({})", name); try { Thread.sleep(5000); name = "wangwu"; log.info("AsyncService -> async03 -> name002({})", name); } catch (InterruptedException e) { e.printStackTrace(); } log.info("AsyncService -> async03 -> name003({})", name); return name; } // 调用异步方法 @GetMapping("/sync03") public String sync03() { log.info("AsyncController -> sync03 -> 001"); //同步方法中调用异步方法 String name = asyncService.async03(); log.info("AsyncController -> sync03 -> name({})", name); return name; } ``` 日志打印顺序如下: ``` 2022-09-07 12:03:33 : AsyncController -> sync03 -> 001 2022-09-07 12:03:33 : AsyncController -> sync03 -> name(null) 2022-09-07 12:03:33 : AsyncService -> async03 -> name001(zhangsan) -- 等待5s打印如下内容 2022-09-07 12:03:38 : AsyncService -> async03 -> name002(wangwu) 2022-09-07 12:03:38 : AsyncService -> async03 -> name003(wangwu) ``` <br/> **2. 如果非要获取异步方法的返回值,可以返回Future类,但是这个方法就不再是异步方法了** ```java // 异步方法,返回值为Future @Async public Future<String> async04() { String name = "zhangsan"; log.info("AsyncService -> async04 -> name001({})", name); try { Thread.sleep(5000); name = "wangwu"; log.info("AsyncService -> async04 -> name002({})", name); } catch (InterruptedException e) { e.printStackTrace(); } log.info("AsyncService -> async04 -> name003({})", name); return new AsyncResult<>(name); } // 调用异步方法 @GetMapping("/sync04") public String sync04() throws ExecutionException, InterruptedException { log.info("AsyncController -> sync04 -> 001"); //同步方法中调用异步方法 String name = asyncService.async04().get(); log.info("AsyncController -> sync04 -> name({})", name); return name; } ``` 日志打印顺序如下,说明异步没有执行。 ``` 2022-09-07 12:07:08 : AsyncController -> sync04 -> 001 2022-09-07 12:07:08 : AsyncService -> async04 -> name001(zhangsan) 2022-09-07 12:07:13 : AsyncService -> async04 -> name002(wangwu) 2022-09-07 12:07:13 : AsyncService -> async04 -> name003(wangwu) 2022-09-07 12:07:13 : AsyncController -> sync04 -> name(wangwu) ``` >[warning]&nbsp;&nbsp;1. 虽然不能获取异步方法的返回值,但是异步方法的返回值可以不是void。<br/> &nbsp;&nbsp;2. 只能返回引用类型,不能返回基本数据类型。