Spingboot项目中异步任务线程池配置方式

95 篇文章 3 订阅
60 篇文章 2 订阅

环境:springboot2.3.9.RELEASE


如果上下文中没有Executor Bean,Spring Boot会自动配置ThreadPoolTaskExecutor,使其具有可自动关联到异步任务执行(@EnableSync)

系统默认配置

public static final String APPLICATION_TASK_EXECUTOR_BEAN_NAME = "applicationTaskExecutor";

@Bean
@ConditionalOnMissingBean
public TaskExecutorBuilder taskExecutorBuilder(TaskExecutionProperties properties,
    ObjectProvider<TaskExecutorCustomizer> taskExecutorCustomizers,
    ObjectProvider<TaskDecorator> taskDecorator) {
  TaskExecutionProperties.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());
  builder = builder.customizers(taskExecutorCustomizers.orderedStream()::iterator);
  builder = builder.taskDecorator(taskDecorator.getIfUnique());
  return builder;
}

@Lazy
@Bean(name = { APPLICATION_TASK_EXECUTOR_BEAN_NAME,AsyncAnnotationBeanPostProcessor.DEFAULT_TASK_EXECUTOR_BEAN_NAME })
@ConditionalOnMissingBean(Executor.class)
public ThreadPoolTaskExecutor applicationTaskExecutor(TaskExecutorBuilder builder) {
  return builder.build();
}

@ConditionalOnMissingBean当前环境中没有Bean是配置该Bean。

可以通过如下属性进行线程池相关参数的配置。

Spingboot项目中异步任务线程池配置方式

 

自定义ThreadPoolTaskExecutor

@Bean
public ThreadPoolTaskExecutor customThreadPoolExecutor() {
  ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor() ;
  executor.setCorePoolSize(10) ;
  executor.setMaxPoolSize(10) ;
  executor.setKeepAliveSeconds(60) ;
  executor.setThreadGroupName("Orders-Group") ;
  executor.setThreadNamePrefix("order-async-") ;
  return executor ;
}

测试是否生效

启动类添加开启异步任务注解

@SpringBootApplication
@EnableAsync
public class SpringBootComprehensiveApplication
@Async
@GetMapping("/task")
public Object task() {
  System.out.println(Thread.currentThread().getName()) ;
  return "success" ;
}

Spingboot项目中异步任务线程池配置方式

 

输出了我们配置的线程信息。

自定义Executor Bean

当系统中存在Executor Bean时,系统会使用SimpleAsyncTaskExecutor线程池

@Bean
public Executor asyncExecutor() {
  ThreadPoolExecutor executor = new ThreadPoolExecutor(10, 10, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(),new ThreadFactory() {
  ThreadGroup group = new ThreadGroup("Orders-JUC-Group") ;
  private final AtomicInteger threadNumber = new AtomicInteger(1);
  String threadPrefix = "order-juc-async-";
      @Override
      public Thread newThread(Runnable r) {
        return new Thread(group, r, threadPrefix + threadNumber.getAndIncrement()) ;
      }
    }) ;
    return executor ;
}

测试:

Spingboot项目中异步任务线程池配置方式

 

注意系统默认的异步任务线程池

@Lazy
@Bean(name = { APPLICATION_TASK_EXECUTOR_BEAN_NAME,AsyncAnnotationBeanPostProcessor.DEFAULT_TASK_EXECUTOR_BEAN_NAME })
@ConditionalOnMissingBean(Executor.class)
public ThreadPoolTaskExecutor applicationTaskExecutor(TaskExecutorBuilder builder) {
  return builder.build();
}

@ConditionalOnMissingBean(Executor.class)注意这里,只有当前没有Executor Bean的时候才会创建ThreadPoolTaskExecutor线程池。所以这时候applicationTaskExecutor Bean也不会生效了。系统中配置的ThreadPoolExecutor Bean并不会应用到异步任务的执行。

注意:现在bean name 是 asyncExecutor,把其改为taskExecutor。再运行

Spingboot项目中异步任务线程池配置方式

 

自定义线程池ThreadPoolExecutor生效了。查看源码
AsyncAnnotationBeanPostProcessor

@Nullable
private Supplier<Executor> executor;
/**
	 * Set the {@link Executor} to use when invoking methods asynchronously.
	 * <p>If not specified, default executor resolution will apply: searching for a
	 * unique {@link TaskExecutor} bean in the context, or for an {@link Executor}
	 * bean named "taskExecutor" otherwise. If neither of the two is resolvable,
	 * a local default executor will be created within the interceptor.
	 * @see AnnotationAsyncExecutionInterceptor#getDefaultExecutor(BeanFactory)
	 * @see #DEFAULT_TASK_EXECUTOR_BEAN_NAME
	 */
public void setExecutor(Executor executor) {
  this.executor = SingletonSupplier.of(executor);
}

注释大意是:在上下文中搜索TaskExecutor Bean,如果没有再找名为taskExecutor 的Bean。

 

自定义AsyncConfigurer实现线程池

通过自定义AsyncConfigurer类可以使用JUC中的ThreadPoolExecutor线程池。

@Component
public class CustomAsyncConfigurer implements AsyncConfigurer {

  private static Logger logger = LoggerFactory.getLogger(CustomAsyncConfigurer.class) ;
	
  @Override
  public Executor getAsyncExecutor() {
    ThreadPoolExecutor executor = new ThreadPoolExecutor(10, 10, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(),new ThreadFactory() {
      ThreadGroup group = new ThreadGroup("Orders-JUC-Group") ;
      private final AtomicInteger threadNumber = new AtomicInteger(1);
      String threadPrefix = "order-juc-async-";
      @Override
      public Thread newThread(Runnable r) {
        return new Thread(group, r, threadPrefix + threadNumber.getAndIncrement()) ;
      }
    }) ;
    return executor ;
  }

  @Override
  public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
    return new AsyncUncaughtExceptionHandler() {
      @Override
      public void handleUncaughtException(Throwable ex, Method method, Object... params) {
        logger.error("method: {}, params: {}, ex: {}", method.getName(), Arrays.toString(params), ex) ;
      }
    };
  }
}

这里查看源码就明白了。

Spingboot项目中异步任务线程池配置方式

 

进入父类:
AbstractAsyncConfiguration.java

Spingboot项目中异步任务线程池配置方式

 

自动装配AsyncConfigurer。

测试:

Spingboot项目中异步任务线程池配置方式

 

自定义的ThreadPoolExecutor已生效。

完毕!!!

给个关注+转发呗谢谢

Spingboot项目中异步任务线程池配置方式

 

Spingboot项目中异步任务线程池配置方式

 

Spingboot项目中异步任务线程池配置方式

 

Spingboot项目中异步任务线程池配置方式

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值