java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > ThreadPoolTaskExecutor线程池管理(解决@Async)

ThreadPoolTaskExecutor线程池管理方式(解决@Async问题)

作者:灵感君

这段描述主要介绍了ThreadPoolTaskExecutor在Spring框架中的应用及其核心参数配置,包括线程池大小、最大线线程数、等待队列容量等关键设置,强调了合理配置的重要性以优化异步任务处理效率

ThreadPoolTaskExecutor介绍

ThreadPoolTaskExecutor是Spring框架提供的线程池管理器,它继承自ThreadPoolExecutor类,并对其进行了一些扩展和封装。

下面是ThreadPoolTaskExecutor的常用参数:

  1. corePoolSize(核心线程数):线程池中保持活动状态的最小线程数。
  2. maxPoolSize(最大线程数):线程池中允许存在的最大线程数,超过该数量的任务会放入等待队列。
  3. keepAliveSeconds(线程活动时间):当线程池中线程数量超过核心线程数时,多余的空闲线程的存活时间。
  4. queueCapacity(等待队列容量):等待队列的容量,用于存放等待执行的任务。
  5. threadNamePrefix(线程名前缀):新创建的线程的名称前缀,默认为task-
  6. rejectedExecutionHandler(拒绝策略):当线程池和等待队列都满了,无法处理新的任务时的处理策略,可选的策略有:
    • AbortPolicy:直接抛出RejectedExecutionException异常,默认策略。
    • CallerRunsPolicy:在调用者的线程中执行该任务。
    • DiscardPolicy:丢弃任务,不抛出异常。
    • DiscardOldestPolicy:丢弃队列中最旧的任务,然后重新尝试执行新的任务。

除了以上常用参数外,ThreadPoolTaskExecutor还提供了一些其他可配置属性和方法来进一步控制线程池的行为。

例如,你可以修改核心线程数、最大线程数和等待队列容量:

executor.setCorePoolSize(10);
executor.setMaxPoolSize(20);
executor.setQueueCapacity(100);

你还可以设置是否允许核心线程超时关闭、是否允许核心线程被回收等高级配置:

executor.setAllowCoreThreadTimeOut(true); // 允许核心线程超时关闭
executor.setWaitForTasksToCompleteOnShutdown(true); // 等待所有任务完成后再关闭线程池
executor.setAwaitTerminationSeconds(60); // 等待终止的时间

这些是ThreadPoolTaskExecutor常用的一些参数和配置选项。

根据具体需求,你可以选择合适的参数来配置线程池,以满足你的业务需求。

实现步骤

配置管理器

@Slf4j
@EnableAsync
@Configuration
public class AsyncConfiguration implements AsyncConfigurer {

    @Primary
    @Bean(name = AsyncExecutionAspectSupport.DEFAULT_TASK_EXECUTOR_BEAN_NAME)
    public ThreadPoolTaskExecutor taskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        // 获取电脑的处理器数量,一般电脑一个处理器有两个逻辑线程
        int num = Runtime.getRuntime().availableProcessors();
        // 核心线程数目 核心线程数最好设置为电脑的逻辑线程总数 + 1,达到最大化利用处理器
        executor.setCorePoolSize(num * 2 + 1);
        // 指定最大线程数
        executor.setMaxPoolSize(200);
        // 队列中最大的数目
        executor.setQueueCapacity(100);
        // 线程名称前缀
        executor.setThreadNamePrefix("taskExecutor-");
        // 拒绝策略:不在新线程中执行任务,而是由调用者所在的线程来执行
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        // 当调度器shutdown被调用时等待当前被调度的任务完成
        executor.setWaitForTasksToCompleteOnShutdown(true);
        // 线程空闲后的最大存活时间
        executor.setKeepAliveSeconds(60);
        // 线程池初始化
        executor.initialize();
        return executor;
    }

    @Override
    public Executor getAsyncExecutor() {
        return taskExecutor();
    }

    @Override
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
        return new CustomAsyncUncaughtExceptionHandler();
    }

    static class CustomAsyncUncaughtExceptionHandler implements AsyncUncaughtExceptionHandler {
        @Override
        public void handleUncaughtException(Throwable ex, Method method, Object... params) {
            log.error(">>> CustomAsyncUncaughtExceptionHandler,class:{}, method: {}, params: {}, error: {}",
                    method.getDeclaringClass().getSimpleName(), method.getName(), Arrays.toString(params),
                    ex.getMessage());
        }
    }

}

测试

@Component
public class MyTask {

    @Async("taskExecutor")
    public void executeAsyncTask() {
        for (int i = 0; i < 10; i++) {
            try {
                Thread.sleep(1000L);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("异步方法打印:" + i);
        }
    }
}
@RestController
@RequestMapping("/test")
@Api(tags = "测试")
public class TestController {

    @Autowired
    private MyTask myTask;

    @RequestMapping(value = "/thread", method = RequestMethod.GET)
    public void thread() {
        myTask.executeAsyncTask();
        System.out.println("异步执行成功!");
    }

}

通过在方法上添加@Async("taskExecutor")注解,指定了使用名为"taskExecutor"的线程池来执行异步任务。

这样,你就可以在整个应用程序中使用同一个全局线程池管理器来执行异步任务。确保在需要使用的类上添加@Component或其他适当的注解,以便Spring Boot能够正确地扫描和管理这些组件。

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

您可能感兴趣的文章:
阅读全文