spring boot 如何使用多線程


spring boot 如何使用多線程

Spring中實現多線程,其實非常簡單,只需要在配置類中添加@EnableAsync就可以使用多線程。在希望執行的並發方法中使用@Async就可以定義一個線程任務。通過spring給我們提供的ThreadPoolTaskExecutor就可以使用線程池。

 

第一步,先在Spring Boot主類中定義一個線程池,比如:

package com.jmxf.core.config;

import java.util.concurrent.Executor;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

@Configuration
@EnableAsync  // 啟用異步任務
public class AsyncConfiguration {

    // 組件計算
    @Bean("zjExecutor")
    public Executor asyncExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        //核心線程數5:線程池創建時候初始化的線程數
        executor.setCorePoolSize(5);
        //最大線程數5:線程池最大的線程數,只有在緩沖隊列滿了之后才會申請超過核心線程數的線程
        executor.setMaxPoolSize(10);
        //緩沖隊列500:用來緩沖執行任務的隊列
        executor.setQueueCapacity(500);
        //允許線程的空閑時間60秒:當超過了核心線程出之外的線程在空閑時間到達之后會被銷毀
        executor.setKeepAliveSeconds(60);
        //線程池名的前綴:設置好了之后可以方便我們定位處理任務所在的線程池
        executor.setThreadNamePrefix("DailyAsync-");
        executor.initialize();
        return executor;
    }
}

有很多你可以配置的東西。默認情況下,使用SimpleAsyncTaskExecutor

第二步,使用線程池

在定義了線程池之后,我們如何讓異步調用的執行任務使用這個線程池中的資源來運行呢?方法非常簡單,我們只需要在@Async注解中指定線程池名即可,比如:

package com.jmxf.service.fkqManage.zj;


import org.springframework.scheduling.annotation.Async;

@Service
public class CentreZj {


    /**
     * 多線程執行 zj計算推數
     * @param fkqZj
     * @throws Exception
     */
    @Async("zjExecutor")
    public CompletableFuture<String> executeZj (FkqZj fkqZj) {
        if(fkqZj == null) return;
        String zjid = fkqZj.getZjid();
        FkqHdzjdm zjdm = getZjdm(zjid);
        String zjlj = zjdm.getZjlj();
        if(StringUtils.isBlank(zjlj)) return;
        Object bean = ApplicationContextProvider.getBean(zjlj);
        Method method;
        try {
            method = bean.getClass().getMethod("refresh",String.class);
            method.invoke(bean,zjid);
        } catch (Exception e) {
            e.printStackTrace();
        } 
    }
    return CompletableFuture.completedFuture(zjid);

}
executeZj方法被標記為Spring的 @Async 注解,表示它將在一個單獨的線程上運行。該方法的返回類型是 CompleetableFuture 而不是 String,這是任何異步服務的要求。

第三步,調用測試

List<CompletableFuture<String>> executeZjs = new ArrayList<>();
        for (FkqZj fkqZj : zjs) {
            CompletableFuture<String> executeZj = centreZj.executeZj(fkqZj);
            executeZjs.add(executeZj);
        }
        //等待所以子線程結束后 返回結果
        for (CompletableFuture<String> completableFuture : executeZjs) {
            CompletableFuture.allOf(completableFuture).join();
        }

 




注意事項
異步方法和調用方法一定要寫在不同的類中 ,如果寫在一個類中,是沒有效果的!
原因:

spring對@Transactional注解時也有類似問題,spring掃描時具有@Transactional注解方法的類時,是生成一個代理類,由代理類去開啟關閉事務,而在同一個類中,方法調用是在類體內執行的,spring無法截獲這個方法調用。

 

 

 

 

使用CompletableFuture.runAsync() 實現局部代碼塊異步

這個方法是簡單的異步執行一個線程,但是它將返回一個CompletableFuture,有了這個CompletableFuture,可以重新組裝和調配,這是和一個普通Runnable不同之處。

public void testAsync(List<List<Object>> listByExcel) {
  // coding...
    ExecutorService executor = Executors.newFixedThreadPool(1);
        CompletableFuture.runAsync(() ->{
            // coding...
        },executor);
  // coding...
}

 


免責聲明!

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



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