異步調用:當咱們執行一個方法時,假如這個方法中有多個耗時的任務須要同時去作,並且又不着急等待這個結果時可讓客戶端當即返回而後,後臺慢慢去計算任務。固然你也能夠選擇等這些任務都執行完了,再返回給客戶端。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秒以後輸出。函數