Spring Boot 异步處理任務

程序員社區 2022-01-07 13:02:09 阅读数:339

spring boot 异步

項目場景:

       現在需要上傳一個Excel錶格,數據量幾萬條,而且,上傳解析後還需要進行計算,然後插入數據庫。

分析:

       上傳和解析,都很簡單,但是,這裏如果使用同步方式,那麼:上傳–>解析–>運算–>插入數據庫;這個過程,前臺的頁面都是等待狀態的,用戶會以為頁面卡死了。所以,這裏需要做异步處理:

1.上傳–>返回正在解析的標志;

2.解析–>運算–>插入數據庫;

此時,當用戶上傳完文件後,頁面立馬跳轉,解析,運算等工作,繼續在後臺進行,而用戶可以不用等待。

Spring Boot 异步任務處理方式

Tip:
        推薦使用 【方式二】:Spring Boot 基於注解方式開啟异步任務處理,可以省去編寫多線程的繁瑣任務,並且只需要@EnableAsync 和 @Async 兩個注解即可解决問題,so 完美

1.同步方式

  controller

 /** * 同步處理 * @return */@RequestMapping(value = "test2",method = RequestMethod.GET)public String test2(){
 loginService.getTest2(); logger.info(Thread.currentThread().getName()+"==========主線程名"); return "同步,正在解析......";}

  serviceImpl

 /**同步方法*/@Overridepublic void getTest2(){
 Building building = new Building(); synchronized (building){
 try {
 for (int i = 1;i <= 100;i++){
 logger.info(Thread.currentThread().getName()+"----------同步:>"+i); building.wait(200); } }catch (Exception ex){
 ex.printStackTrace(); } }}

       這種同步的方式處理,會發現,當這100次循環完成後,頁面才會返回 :同步,正在解析…。當後臺在循環處理時,前臺的頁面始終處於等待狀態。可以發現,使用都是一個線程在處理:
在這裏插入圖片描述

2.异步任務【方式一】

使用線程池,創建新的線程去處理,如下:

  controller

/** * 异步處理1:線程池,創建新線程處理 * @return */@RequestMapping(value = "test3",method = RequestMethod.GET)public String test3(){
 ExecutorService service = Executors.newFixedThreadPool(5); RunnableTask1 task1 = new RunnableTask1(); service.execute(task1); logger.info("=========》當前線程名:"+Thread.currentThread().getName()); return "异步,正在解析......";}

  線程任務

public class RunnableTask1 implements Runnable{
 private final Logger logger = LoggerFactory.getLogger(getClass()); @Override public void run(){
 Building building = new Building(); synchronized (building){
 try {
 for (int i = 1;i <= 100;i++){
 System.out.println(Thread.currentThread().getName()+"----------异步:>"+i); building.wait(200); } }catch (Exception ex){
 ex.printStackTrace(); } } }}

       我們看控制臺會發現:主線程和處理任務的線程,不是一個線程;即:當頁面請求後,主線程會返回我們想要返回的標識,這裏返回的是一個字符串:异步,正在解析…,而線程池新開了一個線程,在後臺處理業務邏輯。所以,此時訪問接口後,會立馬返回,頁面不用等待,處理邏輯在後臺默默進行。控制臺如下:
在這裏插入圖片描述

3.(推薦)异步任務【方式二】

       這種方式,是Spring Boot自身的一種异步方式,使用注解實現,非常方便。我們在想要异步執行的方法上加上@Async注解,在項目啟動類上加上@EnableAsync注解即可。注意:這裏的异步方法,只能在自身之外調用,在本類調用是無效的。

 項目啟動類 SpringbootApplication

@EnableAsync //開啟异步注解功能@SpringBootApplicationpublic class SpringbootApplication {
 public static void main(String[] args) {
 SpringApplication.run(SpringbootApplication .class, args); }}

 controller

@RestController@RequestMapping("tmall")public class LoginController {
 private final org.slf4j.Logger logger = LoggerFactory.getLogger(getClass()); @Autowired private LoginService loginService; /** * 异步處理2:使用springBoot自帶async注解 */ @RequestMapping(value = "test1",method = RequestMethod.GET) public String test1(){
 loginService.getTest1(); logger.info("============>"+Thread.currentThread().getName()); return "异步,正在解析......"; }}

 serviceImpl

/**异步方法 * 有@Async注解的方法,默認就是异步執行的,會在默認的線程池中執行,但是此方法不能在本類調用;啟動類需添加直接開啟异步執行@EnableAsync。 * */@Async@Overridepublic String getTest1(){
 Building building = new Building(); synchronized (building){
 try {
 for (int i = 1;i <= 100;i++){
 logger.info(Thread.currentThread().getName()+"----------异步:>"+i); building.wait(200); } return "執行异步任務完畢"; }catch (Exception ex){
 ex.printStackTrace(); } } return Thread.currentThread().getName()+"執行完畢";}

       看控制臺,會發現,頁面發出請求後,主線程會返回,而內置的線程池會新開線程,在後臺執行任務。此時頁面不用等待,可以繼續其他操作。
在這裏插入圖片描述
       可以看到,很多情况下,异步處理,是一種很常見,而且很高效的方式。相比較需要使用多線程解决异步,我們肯定更喜歡使用 Spring Boo t自帶的注解方式,只用兩個注解即可了


本文為轉載文章,在原文基礎上有所修改,僅用作學習記錄

如果本文對你有所幫助,那就給我點個贊唄

End

版权声明:本文为[程序員社區]所创,转载请带上原文链接,感谢。 https://gsmany.com/2022/01/202201071302085476.html