天天看點

八、SpringBoot整合多線程異步前言一、異步調用實作二、@Async整合線程池

目錄

  • 前言
  • 一、異步調用實作
  • 二、@Async整合線程池

前言

  • @Async實際就是多線程封裝的
  • 異步線程執行方法有可能會非常消耗cpu的資源,是以大的項目建議使用Mq異步實作

一、異步調用實作

  • 1.啟動類需要添加注解

    @EnableAsync

@SpringBootApplication
@EnableAsync
public class App {
    public static void main(String[] args) {
        SpringApplication.run(App.class);
    }
}
           
  • 2.需要執行異步的方法上加上注解

    @Async

    • 注意失效問題:如果異步注解寫目前自己類,有可能aop會失效,無法攔截注解,最終導緻異步注解失效,需要經過代理類調用接口;是以需要将異步的代碼單獨抽取成一個類調用接口
@RestController
@Slf4j
public class MemberService {

    @Autowired
    private MemberServiceAsync memberServiceAsync;

    @RequestMapping("/addMember")
    public String addMember() {
        // 1.資料庫插入資料
        log.info(">01<");

        memberServiceAsync.sms();
        log.info(">04<");
        return "使用者注冊成功";
    }
}
           
@Component
@Slf4j
public class MemberServiceAsync {
    @Async
    public String sms() {
        log.info(">02<");
        try {
            log.info(">正在發送短信..<");
            Thread.sleep(3000);
        } catch (Exception e) {

        }
        log.info(">03<");
        return "短信發送完成!";
    }
}
           
八、SpringBoot整合多線程異步前言一、異步調用實作二、@Async整合線程池

二、@Async整合線程池

  • 1.在第一點的例子中雖然我們實作了異步多線程,但是還有缺點
    • 每次都重新開啟一個線程,這樣非常消耗資源影響效率
    • 我們需要整合線程池來優化,提高程式的性能
      八、SpringBoot整合多線程異步前言一、異步調用實作二、@Async整合線程池
  • 2.項目結構
八、SpringBoot整合多線程異步前言一、異步調用實作二、@Async整合線程池
  • 3.ThreadPoolConfig
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;
    }
}
           
  • 4.在@Async()注解中配置屬性"taskExecutor"
@Component
@Slf4j
public class MemberServiceAsync {
    @Async("taskExecutor")
    public String sms() {
        log.info(">02<");
        try {
            log.info(">正在發送短信..<");
            Thread.sleep(3000);
        } catch (Exception e) {

        }
        log.info(">03<");
        return "短信發送完成!";
    }
    /**
     * 線程池
     */
}