SpringBoot中的异步执行方法详解
作者:yfs1024
源码跟踪
简单描述
在SpringBoot2.0.9之前需要手动自定义线程池(如下2.1), 然后指定线程池的名称
SpringBoot2.0.9以及之前的版本,使用的线程池默认是SimpleAsyncTaskExcutor, 之后的版本使用的是ThreadpoolTaskExecutor
并且不需要手动的创建当前线程池(但往往我们还是会手动指定,具体原因看源码就可以自有判断 )
SpringBoot会自动的扫描两个文件下的配置信息:
所以如果我们写的配置类想让SpringBoot自动扫描到就可以放到两个中的任意一个
我们项目中就是这样使用的:在 spring.factories文件中指定一些配置类相对路径,这样配置类中的指定的Bean就可以放入到IOC容器中了
SpringBoot在org.springframework.boot.autoconfigure.AutoConfiguration.imports118行配置了TaskExecutionAutoConfiguration的位置,这样SpringBoot就可以扫描到当前配置类
TaskExecutionAutoConfiguration
配置类信息如下
@ConditionalOnClass({ThreadPoolTaskExecutor.class}) // 代表如果容器中有这个类,就不在创建 @AutoConfiguration @EnableConfigurationProperties({TaskExecutionProperties.class}) // 配置文件 public class TaskExecutionAutoConfiguration { // 应用程序任务执行器任务名称 applicationTaskExecutor public static final String APPLICATION_TASK_EXECUTOR_BEAN_NAME = "applicationTaskExecutor"; public TaskExecutionAutoConfiguration() { } @Bean @ConditionalOnMissingBean public TaskExecutorBuilder taskExecutorBuilder(TaskExecutionProperties properties, ObjectProvider<TaskExecutorCustomizer> taskExecutorCustomizers, ObjectProvider<TaskDecorator> taskDecorator) { Pool pool = properties.getPool(); TaskExecutorBuilder builder = new TaskExecutorBuilder(); builder = builder.queueCapacity(pool.getQueueCapacity()); builder = builder.corePoolSize(pool.getCoreSize()); builder = builder.maxPoolSize(pool.getMaxSize()); builder = builder.allowCoreThreadTimeOut(pool.isAllowCoreThreadTimeout()); builder = builder.keepAlive(pool.getKeepAlive()); Shutdown shutdown = properties.getShutdown(); builder = builder.awaitTermination(shutdown.isAwaitTermination()); builder = builder.awaitTerminationPeriod(shutdown.getAwaitTerminationPeriod()); builder = builder.threadNamePrefix(properties.getThreadNamePrefix()); Stream var10001 = taskExecutorCustomizers.orderedStream(); var10001.getClass(); builder = builder.customizers(var10001::iterator); builder = builder.taskDecorator((TaskDecorator)taskDecorator.getIfUnique()); return builder; } @Lazy @Bean( name = {"applicationTaskExecutor", "taskExecutor"} ) @ConditionalOnMissingBean({Executor.class}) public ThreadPoolTaskExecutor applicationTaskExecutor(TaskExecutorBuilder builder) { return builder.build(); }
TaskExecutionProperties
配置文件中
定义了线程名 task -
ThreadPoolTaskExecutor
public class ThreadPoolTaskExecutor extends ExecutorConfigurationSupport implements AsyncListenableTaskExecutor, SchedulingTaskExecutor { private final Object poolSizeMonitor = new Object(); private int corePoolSize = 1; private int maxPoolSize = Integer.MAX_VALUE; private int keepAliveSeconds = 60; private int queueCapacity = Integer.MAX_VALUE; private boolean allowCoreThreadTimeOut = false; private boolean prestartAllCoreThreads = false; // ...... ......................省略 // 创建代码 @Override protected ExecutorService initializeExecutor( ThreadFactory threadFactory, RejectedExecutionHandler rejectedExecutionHandler) { BlockingQueue<Runnable> queue = createQueue(this.queueCapacity); ThreadPoolExecutor executor; if (this.taskDecorator != null) { // 还是 new ThreadPoolExecutor executor = new ThreadPoolExecutor( this.corePoolSize, this.maxPoolSize, this.keepAliveSeconds, TimeUnit.SECONDS, queue, threadFactory, rejectedExecutionHandler) { @Override public void execute(Runnable command) { Runnable decorated = taskDecorator.decorate(command); if (decorated != command) { decoratedTaskMap.put(decorated, command); } super.execute(decorated); } }; } else { executor = new ThreadPoolExecutor( this.corePoolSize, this.maxPoolSize, this.keepAliveSeconds, TimeUnit.SECONDS, queue, threadFactory, rejectedExecutionHandler); } if (this.allowCoreThreadTimeOut) { executor.allowCoreThreadTimeOut(true); } if (this.prestartAllCoreThreads) { executor.prestartAllCoreThreads(); } this.threadPoolExecutor = executor; return executor; }
测试代码:
// 注入 @Autowired private ThreadPoolTaskExecutor executor; @Test public void testThreadPool(){ System.out.println(executor); System.out.println("默认前缀:"+executor.getThreadNamePrefix()); System.out.println("默认核心线程数:"+executor.getCorePoolSize()); System.out.println("默认最大线程数:"+executor.getMaxPoolSize()); System.out.println("当前活跃线程数:"+executor.getActiveCount()); System.out.println("临时线程空闲时间:"+executor.getKeepAliveSeconds()); System.out.println("队列最大值:"+executor.getQueueCapacity()); System.out.println("队列数量:"+executor.getQueueSize()); }
结果如下:
org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor@7410c197
默认前缀:task-
默认核心线程数:8
默认最大线程数:2147483647
当前活跃线程数:0
临时线程空闲时间:60
队列最大值:2147483647
队列数量:0
我们可以看到SpringBoot中默认配置的线程池的数量, 很不符合我们的实际要求, 而且还容易发生OOM(Out Of Memory)
所以我们一般是手动指定线程池中的信息
SpringBoot异步执行方法
定义一个配置类
SpringBoot底层对手动注入的Bean采用的名称如果不在@Bean注解后面指定默认采用的是方法名
即: 这里的 generateExchangeCodeExecutor
@Slf4j @Configuration public class PromotionConfig { @Bean public Executor generateExchangeCodeExecutor(){ ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); // 1.核心线程池大小 executor.setCorePoolSize(2); // 2.最大线程池大小 executor.setMaxPoolSize(5); // 3.队列大小 executor.setQueueCapacity(200); // 4.线程名称 executor.setThreadNamePrefix("exchange-code-handler-"); // 5.拒绝策略 executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); executor.initialize(); return executor; } }
在启动类上添加注解
@EnableAsync
在想要异步执行的方法上添加 @Async()注解
并指定ThreadPoolTaskExecutor 执行器的名称
@Override @Async("generateExchangeCodeExecutor") public void asyncGenerateCode(Coupon coupon) { ...... }
到此这篇关于SpringBoot中的异步执行方法详解的文章就介绍到这了,更多相关SpringBoot异步执行内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!