springboot使用@async實現異步線程池


1.介紹

工作中經常涉及異步任務,通常是使用多線程技術,比如線程池ThreadPoolExecutor,但使用Executors容易產生OOM,需要手動使用ThreadPoolExecutor創建線程池;在springboot使用 @async 可以實現異步調用,配置線程池參數,可以簡單的實現多線程的線程池效果,從而簡化開發,避免OOM;

2.異步調用,無返回結果

首先在啟動類上加上@EnableAsync 注解

@SpringBootApplication
@EnableAsync
public class AsyncApplication {
    public static void main(String[] args) {
        SpringApplication.run(AsyncApplication.class,args);
    }
}

在函數上標上@sync注解,表示異步調用

@Async
public void exec2(){
    try {
        Thread.sleep(3000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    log.info("exec2 執行完畢");
}
@GetMapping("exec2")
public String exec2(){
    mainService.exec2();
    return "exec2";
}

測試:瀏覽器立即返回結果,3秒之后后台才打印輸出日志

2.異步調用,有返回值

@Async
public Future<String> exec3_1(){
    try {
        Thread.sleep(2500);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    log.info("exec3_1 執行完畢");
    return new AsyncResult<>("exec3_1");
}

@Async
public Future<String> exec3_2(){
    try {
        Thread.sleep(3000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    log.info("exec3_2 執行完畢");
    return new AsyncResult<>("exec3_2");
}
@GetMapping("exec3")
public String exec3() throws ExecutionException, InterruptedException {
    Future<String> exec3_1 = mainService.exec3_1();
    Future<String> exec3_2 = mainService.exec3_2();

    String result="";

    while (true){
        if(exec3_1.isDone() && exec3_2.isDone()){
            result=exec3_1.get()+"--"+exec3_2.get();
            break;
        }
    }
    return result;
}

測試:3秒后瀏覽器返回結果

4.線程池

在異步掉用中使用的@Async 注解,默認的線程池大小如下
# 核心線程數
spring.task.execution.pool.core-size=8  
# 最大線程數
spring.task.execution.pool.max-size=16
# 空閑線程存活時間
spring.task.execution.pool.keep-alive=60s
# 是否允許核心線程超時
spring.task.execution.pool.allow-core-thread-timeout=true
# 線程隊列數量
spring.task.execution.pool.queue-capacity=100
# 線程關閉等待
spring.task.execution.shutdown.await-termination=false
spring.task.execution.shutdown.await-termination-period=
# 線程名稱前綴
spring.task.execution.thread-name-prefix=task-

一般情況下,我們都需要手動創建線程池,使用 ThreadPoolTaskExecutor 類進行配置

@Configuration
public class PoolConfig {

    @Bean
    public TaskExecutor taskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        // 設置核心線程數
        executor.setCorePoolSize(10);
        // 設置最大線程數
        executor.setMaxPoolSize(15);
        // 設置隊列容量
        executor.setQueueCapacity(20);
        // 設置線程活躍時間(秒)
        executor.setKeepAliveSeconds(60);
        // 設置默認線程名稱
        executor.setThreadNamePrefix("zszxz-");
        // 設置拒絕策略
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        // 等待所有任務結束后再關閉線程池
        executor.setWaitForTasksToCompleteOnShutdown(true);
        return executor;
    }
}


免責聲明!

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



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