SpringBoot-27- @Async实现异步调用
什么是异步调用
异步调用是相对于同步调用的,同步调用是按照顺序进行执行任务,只有上一个任务执行完成下一个任务才能执行,异步调用是指在按照顺序执行任务的过程中不需要等待任务结果的出现,就可以顺序执行下一个任务。
异步处理的方式:
- Java异步处理:Thread/Runnable、Callable/Future
- Servlet 3.0异步处理: asyncSupported、AsyncContext
- Spring MVC异步处理: @Async、AsyncTaskExecutor
SpringBoot自身没有对异步调用做很大的变动,基本还是使用SpringMVC的@Async
开启异步调用配置
@EnableAsync @Configuration public class MyEnableAsyncConfig { }
注解:在使用**@EnableWebMvc**注解的时候也可以开启异步调用,但是在SpringBoot中使用异步调用会使得SpringBoot的AutoConfig一部分功能失效。
定义线程池
定义一个或者多个线程池
@EnableAsync @Configuration public class MyEnableAsyncConfig { @Bean(name = "threadPoolTaskExecutor1") public Executor taskExecutor1() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setCorePoolSize(10); executor.setMaxPoolSize(20); executor.setQueueCapacity(200); executor.setKeepAliveSeconds(60); executor.setThreadNamePrefix("threadPoolTaskExecutor1-"); executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); return executor; } @Bean(name = "threadPoolTaskExecutor2") public Executor threadPoolTaskExecutor2() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setCorePoolSize(10); executor.setMaxPoolSize(20); executor.setQueueCapacity(200); executor.setKeepAliveSeconds(60); executor.setThreadNamePrefix("threadPoolTaskExecutor2-"); executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); return executor; } }
我们使用ThreadPoolTaskExecutor创建线程池,其参数配置如下:
CorePoolSize:设置核心线程数,线程池创建的时候创建线程的个数
MaxPoolSize:最大线程数,在换成队列满以后才会申请超过核心线程的线程
QueueCapacity:缓冲队列,用来缓冲执行任务的队列
KeepAliveSeconds:当超过了核心线程数之外的线程在空闲时间到达之后会被销毁
ThreadNamePrefix:线程名称前缀
定义异步调用方法
异步调用方法有两种一个是没有返回值的,一种是有返回值的,具体实现如下:
@Component public class ComponentTask { public static Random random =new Random(); /** * 无返回值 */ @Async("threadPoolTaskExecutor2") public void asyncMethodWithVoidReturnType_One() throws InterruptedException { System.out.println("开始做asyncMethodWithVoidReturnType_One"); long start = System.currentTimeMillis(); Thread.sleep(random.nextInt(1000)); long end = System.currentTimeMillis(); System.out.println("完成asyncMethodWithVoidReturnType_One,耗时:" + (end - start) + "毫秒"+" threadname:"+Thread.currentThread().getName()); } @Async("threadPoolTaskExecutor1") public void asyncMethodWithVoidReturnType_Two() throws InterruptedException { System.out.println("开始做asyncMethodWithVoidReturnType_Two"); long start = System.currentTimeMillis(); Thread.sleep(random.nextInt(2000)); long end = System.currentTimeMillis(); System.out.println("完成asyncMethodWithVoidReturnType_Two,耗时:" + (end - start) + "毫秒" +" threadname:"+Thread.currentThread().getName()); } @Async("threadPoolTaskExecutor1") public void asyncMethodWithVoidReturnType_Three() throws InterruptedException { System.out.println("开始做asyncMethodWithVoidReturnType_Three"); long start = System.currentTimeMillis(); Thread.sleep(random.nextInt(3000)); long end = System.currentTimeMillis(); System.out.println("完成asyncMethodWithVoidReturnType_Three,耗时:" + (end - start) + "毫秒"+ " threadname:"+Thread.currentThread().getName()); } /** * 有返回值的 * @return */ @Async("threadPoolTaskExecutor1") public Future<String> asyncMethodWithReturnType_One() throws InterruptedException { System.out.println("开始asyncMethodWithReturnType_One"); long start = System.currentTimeMillis(); Thread.sleep(random.nextInt(10000)); long end = System.currentTimeMillis(); System.out.println("完成asyncMethodWithReturnType_One,耗时:" + (end - start) + "毫秒"); return new AsyncResult<>("任务一完成"); } }
在多线程池的时候,我们需要在@Async()指定线程池名称**@Async(“threadPoolTaskExecutor1”)**
单元测试
@SpringBootTest class SpringBootPart27ApplicationTests { @Autowired private ComponentTask componentTask; @Test void contextLoads() throws InterruptedException { componentTask.asyncMethodWithVoidReturnType_One(); componentTask.asyncMethodWithVoidReturnType_Two(); componentTask.asyncMethodWithVoidReturnType_Three(); Thread.currentThread().join(); } }
在单元测试用例中,注入Task对象,并在测试用例中执行asyncMethodWithVoidReturnType_One、asyncMethodWithVoidReturnType_Two()、asyncMethodWithVoidReturnType_Three()三个函数。
执行结果如下:
开始做asyncMethodWithVoidReturnType_One 开始做asyncMethodWithVoidReturnType_Two 开始做asyncMethodWithVoidReturnType_Three 完成asyncMethodWithVoidReturnType_One,耗时:435毫秒 threadname:threadPoolTaskExecutor2-1 完成asyncMethodWithVoidReturnType_Two,耗时:1885毫秒 threadname:threadPoolTaskExecutor1-1 完成asyncMethodWithVoidReturnType_Three,耗时:1904毫秒 threadname:threadPoolTaskExecutor1-2