异步调用:当咱们执行一个方法时,假如这个方法中有多个耗时的任务须要同时去作,并且又不着急等待这个结果时可让客户端当即返回而后,后台慢慢去计算任务。固然你也能够选择等这些任务都执行完了,再返回给客户端。java
若是咱们须要在 SpringBoot 实现异步编程的话,经过 Spring 提供的两个注解会让这件事情变的很是简单。web
@EnableAsync
:经过在配置类或者Main类上加@EnableAsync开启对异步方法的支持。@Async
能够做用在类上或者方法上,做用在类上表明这个类的全部方法都是异步方法。不少人对于 TaskExecutor 不是太了解,因此咱们花一点篇幅先介绍一下这个东西。从名字就能看出它是任务的执行者,它领导执行着线程来处理任务,就像司令官同样,而咱们的线程就比如一只只军队同样,这些军队能够异步对敌人进行打击👊。spring
Spring 提供了TaskExecutor
接口做为任务执行者的抽象,它和java.util.concurrent
包下的Executor
接口很像。稍微不一样的 TaskExecutor
接口用到了 Java 8 的语法@FunctionalInterface
声明这个接口是一个函数式接口。编程
若是没有自定义Executor, Spring 将建立一个 SimpleAsyncTaskExecutor
并使用它。springboot
1 package com.test.configure; 2 3 import org.springframework.context.annotation.Bean; 4 import org.springframework.context.annotation.Configuration; 5 import org.springframework.scheduling.annotation.AsyncConfigurer; 6 import org.springframework.scheduling.annotation.EnableAsync; 7 import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; 8 9 import java.util.concurrent.Executor; 10 import java.util.concurrent.ThreadPoolExecutor; 11 12 @Configuration 13 @EnableAsync 14 public class AsyncConfig implements AsyncConfigurer { 15 16 private static final int CORE_POOL_SIZE = 6; 17 private static final int MAX_POOL_SIZE = 10; 18 private static final int QUEUE_CAPACITY = 100; 19 20 @Bean 21 public Executor taskExecutor() { 22 // Spring 默认配置是核心线程数大小为1,最大线程容量大小不受限制,队列容量也不受限制。 23 ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); 24 // 核心线程数 25 executor.setCorePoolSize(CORE_POOL_SIZE); 26 // 最大线程数 27 executor.setMaxPoolSize(MAX_POOL_SIZE); 28 // 队列大小 29 executor.setQueueCapacity(QUEUE_CAPACITY); 30 // 当最大池已满时,此策略保证不会丢失任务请求,可是可能会影响应用程序总体性能。 31 executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); 32 executor.setThreadNamePrefix("My ThreadPoolTaskExecutor-"); 33 executor.initialize(); 34 return executor; 35 } 36 }
Spring 默认使用的是 ThreadPoolExecutor.AbortPolicy
。在Spring的默认状况下,ThreadPoolExecutor
将抛出 RejectedExecutionException
来拒绝新来的任务 ,这表明你将丢失对这个任务的处理。 对于可伸缩的应用程序,建议使用 ThreadPoolExecutor.CallerRunsPolicy
。当最大池被填满时,此策略为咱们提供可伸缩队列。app
ThreadPoolTaskExecutor
饱和策略定义:异步
若是当前同时运行的线程数量达到最大线程数量时,ThreadPoolTaskExecutor
定义一些策略:async
RejectedExecutionException
来拒绝新任务的处理。1 package com.test.service; 2 3 import org.springframework.scheduling.annotation.Async; 4 import org.springframework.stereotype.Service; 5 6 import java.text.SimpleDateFormat; 7 import java.util.Date; 8 9 @Service 10 public class AsyncService { 11 12 @Async 13 public void test() { 14 SimpleDateFormat sdf = new SimpleDateFormat("YYYY-MM-dd HH:mm:ss"); 15 String start = sdf.format(new Date()); 16 try { 17 Thread.sleep(3000); 18 } catch (InterruptedException e) { 19 e.printStackTrace(); 20 } 21 System.out.println("startTime --->" +start + "EndTime --->" + sdf.format(new Date())); 22 } 23 }
1 package com.test.async.controller; 2 3 import com.test.service.AsyncService; 4 import org.springframework.beans.factory.annotation.Autowired; 5 import org.springframework.scheduling.annotation.Async; 6 import org.springframework.web.bind.annotation.RequestMapping; 7 import org.springframework.web.bind.annotation.RestController; 8 9 import java.util.HashMap; 10 11 @RestController 12 @RequestMapping(value = "/async") 13 public class AsyncController { 14 15 @Autowired 16 private AsyncService asyncService; 17 18 19 @RequestMapping(value = "/test") 20 public HashMap<String,String> test() { 21 HashMap<String,String> map = new HashMap<>(); 22 map.put("name","libai"); 23 asyncService.test(); 24 return map; 25 } 26 }
测试结果:异步编程
startTime --->2019-10-28 16:34:48 EndTime --->2019-10-28 16:34:51 startTime --->2019-10-28 16:34:48 EndTime --->2019-10-28 16:34:51 startTime --->2019-10-28 16:34:48 EndTime --->2019-10-28 16:34:51 startTime --->2019-10-28 16:34:57 EndTime --->2019-10-28 16:35:00 startTime --->2019-10-28 16:34:57 EndTime --->2019-10-28 16:35:00
请求会当即返回,而控制台的输出会在3秒以后输出。函数