SpringBoot之SpringBoot整合異步線程調用注解
理念:
為了快速響應瀏覽器,開啟多線程執行任務
但是有一個缺點,會增加CPU資源的消耗,所以大的項目推薦使用MQ消息隊列
編寫代碼:
@GetMapping("/addDB") public String addDB() { // 模擬數據交互 log.info("<01>"); sms(); log.info("<04>"); return "用戶注冊成功"; } /** * 模擬發送短信 * * @return */ public String sms() { log.info("<02>"); try { log.info("正在發送短信..."); Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } return "短信發送完成"; }
這個接口最少需要4秒才能返回,如果發送短信時間更長,返回時間增加,這樣用戶的體驗就非常不好
啟動項目測試
他是單線程去執行的,看過Tomcat的應該也知道,tomcat會為每一次請求從他的線程池中單獨拿一個線程去執行,所以它是單線程 的
所以這里就可以使用Spring提供的異步注解
異步注解的使用:
在方法上添加@Async注解
並且在啟動類中開啟異步注解
啟動測試:
不對呀,這還是單線程呀
異步注解失效問題解決:
需要把sms方法單獨提取成一個類
package com.springboot.demo.async; import lombok.extern.slf4j.Slf4j; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Component; /** * @author ZYGisComputer */ @Slf4j @Component public class SmsService { /** * 模擬發送短信 * * @return */ @Async public String sms() { log.info("<02>"); try { log.info("正在發送短信..."); Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } return "短信發送完成"; } }
通過Autowirld的方式注入使用
再次測試
可以看到執行成功了,並且也是不同的線程,但是他這樣都是每次都是new一個新的線程,這顯然是不合理的,因為使用線程就應該考慮采用線程池
異步注解整合線程池:
創建config包,並在下面創建ThreadPoolConfig.java
package com.springboot.demo.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.task.TaskExecutor; import org.springframework.scheduling.annotation.EnableAsync; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import java.util.concurrent.ThreadPoolExecutor; @Configuration @EnableAsync public class ThreadPoolConfig { /** * 每秒需要多少個線程處理? * tasks/(1/taskcost) */ private int corePoolSize = 3; /** * 線程池維護線程的最大數量 * (max(tasks)- queueCapacity)/(1/taskcost) */ private int maxPoolSize = 3; /** * 緩存隊列 * (coreSizePool/taskcost)*responsetime */ private int queueCapacity = 10; /** * 允許的空閑時間 * 默認為60 */ private int keepAlive = 100; @Bean public TaskExecutor taskExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); // 設置核心線程數 executor.setCorePoolSize(corePoolSize); // 設置最大線程數 executor.setMaxPoolSize(maxPoolSize); // 設置隊列容量 executor.setQueueCapacity(queueCapacity); // 設置允許的空閑時間(秒) //executor.setKeepAliveSeconds(keepAlive); // 設置默認線程名稱 executor.setThreadNamePrefix("thread-"); // 設置拒絕策略rejection-policy:當pool已經達到max size的時候,如何處理新任務 // CALLER_RUNS:不在新線程中執行任務,而是有調用者所在的線程來執行 executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); // 等待所有任務結束后再關閉線程池 executor.setWaitForTasksToCompleteOnShutdown(true); return executor; } }
在@Async注解中配置線程池名稱就可以
啟動項目測試:
2021-01-26 18:18:53,820 [http-nio-8082-exec-1] INFO (HelloService.java:76)- <01> 2021-01-26 18:18:53,823 [http-nio-8082-exec-1] INFO (HelloService.java:78)- <04> 2021-01-26 18:18:53,823 [http-nio-8082-exec-1] INFO (LogAspect.java:50)- RESPONSE : 用戶注冊成功 2021-01-26 18:18:53,829 [thread-1] INFO (SmsService.java:24)- <02> 2021-01-26 18:18:53,831 [thread-1] INFO (SmsService.java:26)- 正在發送短信... <執行定時任務>:18:18:56 <執行定時任務>:18:19:01 2021-01-26 18:19:01,340 [http-nio-8082-exec-3] INFO (LogAspect.java:37)- URL : http://localhost:8082/addDB 2021-01-26 18:19:01,341 [http-nio-8082-exec-3] INFO (LogAspect.java:38)- HTTP_METHOD : GET 2021-01-26 18:19:01,341 [http-nio-8082-exec-3] INFO (LogAspect.java:39)- IP : 0:0:0:0:0:0:0:1 2021-01-26 18:19:01,341 [http-nio-8082-exec-3] INFO (HelloService.java:76)- <01> 2021-01-26 18:19:01,342 [http-nio-8082-exec-3] INFO (HelloService.java:78)- <04> 2021-01-26 18:19:01,342 [thread-2] INFO (SmsService.java:24)- <02> 2021-01-26 18:19:01,342 [thread-2] INFO (SmsService.java:26)- 正在發送短信... 2021-01-26 18:19:01,342 [http-nio-8082-exec-3] INFO (LogAspect.java:50)- RESPONSE : 用戶注冊成功 2021-01-26 18:19:01,922 [http-nio-8082-exec-4] INFO (LogAspect.java:37)- URL : http://localhost:8082/addDB 2021-01-26 18:19:01,922 [http-nio-8082-exec-4] INFO (LogAspect.java:38)- HTTP_METHOD : GET 2021-01-26 18:19:01,923 [http-nio-8082-exec-4] INFO (LogAspect.java:39)- IP : 0:0:0:0:0:0:0:1 2021-01-26 18:19:01,923 [http-nio-8082-exec-4] INFO (HelloService.java:76)- <01> 2021-01-26 18:19:01,923 [http-nio-8082-exec-4] INFO (HelloService.java:78)- <04> 2021-01-26 18:19:01,924 [thread-3] INFO (SmsService.java:24)- <02> 2021-01-26 18:19:01,924 [http-nio-8082-exec-4] INFO (LogAspect.java:50)- RESPONSE : 用戶注冊成功 2021-01-26 18:19:01,924 [thread-3] INFO (SmsService.java:26)- 正在發送短信... 2021-01-26 18:19:02,559 [http-nio-8082-exec-2] INFO (LogAspect.java:37)- URL : http://localhost:8082/addDB 2021-01-26 18:19:02,559 [http-nio-8082-exec-2] INFO (LogAspect.java:38)- HTTP_METHOD : GET 2021-01-26 18:19:02,559 [http-nio-8082-exec-2] INFO (LogAspect.java:39)- IP : 0:0:0:0:0:0:0:1 2021-01-26 18:19:02,559 [http-nio-8082-exec-2] INFO (HelloService.java:76)- <01> 2021-01-26 18:19:02,560 [thread-1] INFO (SmsService.java:24)- <02> 2021-01-26 18:19:02,560 [http-nio-8082-exec-2] INFO (HelloService.java:78)- <04> 2021-01-26 18:19:02,560 [thread-1] INFO (SmsService.java:26)- 正在發送短信... 2021-01-26 18:19:02,560 [http-nio-8082-exec-2] INFO (LogAspect.java:50)- RESPONSE : 用戶注冊成功
可以看到使用完成thread-3之后使用的又是thread-1了,線程池的參數可以根據自己項目的實際情況調整,不懂線程池的可以去看看我寫的《線程池理念分析及其手寫》
到此整合異步注解完成
作者:彼岸舞
時間:2021\01\26
內容關於:SpringBoot
本文來源於網絡,只做技術分享,一概不負任何責任