Spring boot 自定义ThreadPoolTaskExecutor 线程池并进行异步操作

2022/1/22 23:04:16

本文主要是介绍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 注解时,不用显示生命线程池的方式就可以使用自定义的线程池。

    

    学习ThreadPoolExecutor 更多可以参考这篇文章:Java线程池实现原理及其在美团业务中的实践

 

 

 

 

name="threadPoolExecutor"


这篇关于Spring boot 自定义ThreadPoolTaskExecutor 线程池并进行异步操作的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程