Spring boot 自定義ThreadPoolTaskExecutor 線程池並進行異步操作


本文為博主原創,轉載請注明出處:

1. 使用 ThreadPoolTaskExecutor  封裝自定義配置的線程池Bean

  ThreadPoolTaskExecutor 是Spring 中封裝的一個類,spring boot中常用 ThreadPoolTaskExecutor 創建線程池,並把它注入到 IOC 容器中,從而可以全局進行使用。

   如下為使用 ThreadPoolTaskExecutor  創建的自定義配置的 線程池類:

import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.annotation.EnableAsync; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import java.util.concurrent.Executor; @Configuration @EnableAsync public class ThreadPoolExecutorConfig { @Bean(name="threadPoolExecutor") public Executor threadPoolExecutor(){ ThreadPoolTaskExecutor threadPoolExecutor = new ThreadPoolTaskExecutor(); int processNum = Runtime.getRuntime().availableProcessors(); // 返回可用處理器的Java虛擬機的數量
        int corePoolSize = (int) (processNum / (1 - 0.2)); int maxPoolSize = (int) (processNum / (1 - 0.5)); threadPoolExecutor.setCorePoolSize(corePoolSize); // 核心池大小
        threadPoolExecutor.setMaxPoolSize(maxPoolSize); // 最大線程數
        threadPoolExecutor.setQueueCapacity(maxPoolSize * 1000); // 隊列程度
 threadPoolExecutor.setThreadPriority(Thread.MAX_PRIORITY); threadPoolExecutor.setDaemon(false); threadPoolExecutor.setKeepAliveSeconds(300);// 線程空閑時間
        threadPoolExecutor.setThreadNamePrefix("test-Executor-"); // 線程名字前綴
        return threadPoolExecutor; } }

  @EnableAsync是與@Async配合使用,用於執行異步任務

  使用示例:

@Service
public class SpringExecutorTest {
    @Autowired
    private Executor threadPoolExecutor;

    public void test(){
        AtomicInteger num = new AtomicInteger(0);
        for (int i = 0; i < 5; i++) {
            threadPoolExecutor.execute(()->{
                num.incrementAndGet();
            });
        }
        System.out.println(num.get());
    }
}

2. 與 @Async 注解使用

    @Async("threadPoolExecutor") public void asyncTest(){ log.error("threadPoolExecutor asyncTest start"); }

  需要注意的是,在使用 @Async 注解時,想使用自定義的 Executor 線程池配置,則需要在 @Async 注解上聲明線程池的名稱,否則會使用默認的線程池配置。

  若想在使用@Async 注解時,不顯示聲明線程池,且使用定義線程池的配置,可采用以下方式進行配置:

import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.lang.reflect.Method;
import java.util.concurrent.Executor;

@Slf4j
@Configuration
public class NativeAsyncTaskExecutePool implements AsyncConfigurer {
    @Override
    public Executor getAsyncExecutor() {
        ThreadPoolTaskExecutor threadPoolExecutor = new ThreadPoolTaskExecutor();
        int processNum = Runtime.getRuntime().availableProcessors(); // 返回可用處理器的Java虛擬機的數量
        int corePoolSize = (int) (processNum / (1 - 0.2));
        int maxPoolSize = (int) (processNum / (1 - 0.5));
        threadPoolExecutor.setCorePoolSize(corePoolSize); // 核心池大小
        threadPoolExecutor.setMaxPoolSize(maxPoolSize); // 最大線程數
        threadPoolExecutor.setQueueCapacity(maxPoolSize * 1000); // 隊列程度
        threadPoolExecutor.setThreadPriority(Thread.MAX_PRIORITY);
        threadPoolExecutor.setDaemon(false);
        threadPoolExecutor.setKeepAliveSeconds(300);// 線程空閑時間
        threadPoolExecutor.setThreadNamePrefix("test-Executor-"); // 線程名字前綴
        return threadPoolExecutor;
    }

    /**
     *  異步任務中異常處理
     * @return
     */
    @Override
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
        return new AsyncUncaughtExceptionHandler() {
            @Override
            public void handleUncaughtException(Throwable arg0, Method arg1, Object... arg2) {
                log.error("=========================="+arg0.getMessage()+"=======================", arg0);
                log.error("exception method:"+arg1.getName());
            }
        };
    }
}

  當使用以上的方式時,可在使用 @Async 注解時,不用顯示生命線程池的方式就可以使用自定義的線程池。

3.如何設置核心線程數

  對於ThreadPoolTaskExecutorcorePoolSize,一般來說可以根據任務的性質、數量、執行時間等因素進行靈活調整,具體的配置需要根據實際情況來決定。這里提供一些核心線程數設置的建議:

  1. 根據任務的性質來設置corePoolSize

  如果任務量較少且每個任務都非常耗時,可以適當減少核心線程數以節省資源,例如將corePoolSize設置為2-3;如果有大量的耗時短的任務,可以適當增加核心線程數,例如將corePoolSize設置為10-20等。

  1. 根據CPU核心數來設置corePoolSize

  通常情況下,corePoolSize建議設置為CPU核心數的2倍,這樣可以保證資源的最大利用。但需要注意的是,當任務的處理時間較長時(例如IO操作),可以適當增加corePoolSize以避免線程空閑等待。

 

    學習ThreadPoolExecutor 更多可以參考這篇文章:Java線程池實現原理及其在美團業務中的實踐

 


免責聲明!

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



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