SpringBoot異步編程

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

SpringBoot 異步編程實戰

若是咱們須要在 SpringBoot 實現異步編程的話,經過 Spring 提供的兩個註解會讓這件事情變的很是簡單。web

  1. @EnableAsync:經過在配置類或者Main類上加@EnableAsync開啓對異步方法的支持。
  2. @Async 能夠做用在類上或者方法上,做用在類上表明這個類的全部方法都是異步方法。

1. 自定義 TaskExecutor

不少人對於 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

  • ThreadPoolExecutor.AbortPolicy:拋出 RejectedExecutionException來拒絕新任務的處理。
  • ThreadPoolExecutor.CallerRunsPolicy:調用執行本身的線程運行任務。您不會任務請求。可是這種策略會下降對於新任務提交速度,影響程序的總體性能。另外,這個策略喜歡增長隊列容量。若是您的應用程序能夠承受此延遲而且你不能任務丟棄任何一個任務請求的話,你能夠選擇這個策略。
  • ThreadPoolExecutor.DiscardPolicy: 不處理新任務,直接丟棄掉。
  • ThreadPoolExecutor.DiscardOldestPolicy: 此策略將丟棄最先的未處理的任務請求。

2. 編寫一個異步的方法

 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 }

 

 

3. 測試編寫的異步方法

 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秒以後輸出。函數

相關文章
相關標籤/搜索