SpringBoot之SpringBoot整合異步線程調用注解


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

本文來源於網絡,只做技術分享,一概不負任何責任


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM