异步调用对应的是同步调用,同步调用可以理解为按照定义的顺序依次执行,有序性;异步调用在执行的时候不需要等待上一个指令调用结束就可以继续执行。
我们将在创建一个 Spring Boot 工程来说明。具体工程可以参考github代码 github
pom 依赖如下:
1 |
|
启动类如下:
1 |
|
定义线程池
1 | package com.demo.async.config; |
代码中我们通过 ThreadPoolTaskExecutor 创建了一个线程池。参数含义如下所示:
- corePoolSize:线程池创建的核心线程数
- maxPoolSize:线程池最大线程池数量,当任务数超过corePoolSize以及缓冲队列也满了以后才会申请的线程数量。
- setKeepAliveSeconds: 允许线程空闲时间60秒,当maxPoolSize的线程在空闲时间到达的时候销毁。
- ThreadNamePrefix:线程的前缀任务名字。
- RejectedExecutionHandler:当线程池没有处理能力的时候,该策略会直接在 execute 方法的调用线程中运行被拒绝的任务;如果执行程序已关闭,则会丢弃该任务
使用实战
1 | package com.demo.async.service; |
异步任务服务类
1 | package com.demo.async.task; |
单元测试
1 | package com.demo.async; |
结果
1 | 2020-01-02 15:28:52.392 INFO 35807 --- [ main] com.demo.async.service.OrderService : 开始做任务1:下单成功 |
可以看到有的线程的名字就是我们线程池定义的前缀,说明使用了线程池异步执行。其中我们示范了一个错误的使用案例 otherJob(),并没有异步执行。
原因:
spring 在扫描bean的时候会扫描方法上是否包含@Async注解,如果包含,spring会为这个bean动态地生成一个子类(即代理类,proxy),代理类是继承原来那个bean的。此时,当这个有注解的方法被调用的时候,实际上是由代理类来调用的,代理类在调用时增加异步作用。然而,如果这个有注解的方法是被同一个类中的其他方法调用的,那么该方法的调用并没有通过代理类,而是直接通过原来的那个 bean 也就是 this. method,所以就没有增加异步作用,我们看到的现象就是@Async注解无效。