SpringBoot中的ThreadPoolTaskExecutor

SpringBoot中的ThreadPoolTaskExecutor

一、官方文档说明

ThreadPoolTaskExecutor是SpringBoot提供的默认线程池 。也就是说如果没有自定义线程池,那么会自动装配这个默认的。

1.1、查看官方文档ThreadPoolTaskExecutor说明

In the absence of an Executor bean in the context, Spring Boot auto-configures a ThreadPoolTaskExecutor with sensible defaults that can be automatically associated to asynchronous task execution (@EnableAsync) and Spring MVC asynchronous request processing.

If you have defined a custom Executor in the context, regular task execution (that is @EnableAsync) will use it transparently but the Spring MVC support will not be configured as it requires an AsyncTaskExecutor implementation (named applicationTaskExecutor). Depending on your target arrangement, you could change your Executor into a ThreadPoolTaskExecutor or define both a ThreadPoolTaskExecutor and an AsyncConfigurer wrapping your custom Executor.

如果自定义了Executor 类型的bean存入到容器中

  • 1、在@EnableAsync使用的时候,需要显示的指定线程池;
  • 2、如果需要Spring MVC需要使用到异步任务来进行支持,那么需要将Executor 类型的bean命名成applicationTaskExecutor;

The auto-configured TaskExecutorBuilder allows you to easily create instances that reproduce what the auto-configuration does by default.

1.2、ThreadPoolTaskExecutor自动配置类

详细文档说明:

https://docs.spring.io/spring-boot/docs/current/reference/html/features.html#features.task-execution-and-scheduling

二、ThreadPoolTaskExecutor介绍

2.1、默认参数介绍

ThreadPoolExecutor:这个是JAVA自己实现的线程池执行类,基本上创建线程池都是通过这个类进行的创建!
ThreadPoolTaskExecutor :这个是SpringBoot基于ThreadPoolExecutor实现的一个线程池执行类

这是默认提供的几个配置参数看一下

拒绝策略默认是超出后抛出RejectedExecutionException异常并直接丢弃。

2.2、自动配置类配置属性

@ConfigurationProperties("spring.task.execution")
public class TaskExecutionProperties {

	private final Pool pool = new Pool();

	private final Shutdown shutdown = new Shutdown();

	/**
	 * Prefix to use for the names of newly created threads.
	 */
	private String threadNamePrefix = "task-";

	public Pool getPool() {
		return this.pool;
	}

	public Shutdown getShutdown() {
		return this.shutdown;
	}

	public String getThreadNamePrefix() {
		return this.threadNamePrefix;
	}

	public void setThreadNamePrefix(String threadNamePrefix) {
		this.threadNamePrefix = threadNamePrefix;
	}

	public static class Pool {

		/**
		 * Queue capacity. An unbounded capacity does not increase the pool and therefore
		 * ignores the "max-size" property.
		 */
		private int queueCapacity = Integer.MAX_VALUE;

		/**
		 * Core number of threads.
		 */
		private int coreSize = 8;

		/**
		 * Maximum allowed number of threads. If tasks are filling up the queue, the pool
		 * can expand up to that size to accommodate the load. Ignored if the queue is
		 * unbounded.
		 */
		private int maxSize = Integer.MAX_VALUE;

		/**
		 * Whether core threads are allowed to time out. This enables dynamic growing and
		 * shrinking of the pool.
		 */
		private boolean allowCoreThreadTimeout = true;

		/**
		 * Time limit for which threads may remain idle before being terminated.
		 */
		private Duration keepAlive = Duration.ofSeconds(60);

		public int getQueueCapacity() {
			return this.queueCapacity;
		}

		public void setQueueCapacity(int queueCapacity) {
			this.queueCapacity = queueCapacity;
		}

		public int getCoreSize() {
			return this.coreSize;
		}

		public void setCoreSize(int coreSize) {
			this.coreSize = coreSize;
		}

		public int getMaxSize() {
			return this.maxSize;
		}

		public void setMaxSize(int maxSize) {
			this.maxSize = maxSize;
		}

		public boolean isAllowCoreThreadTimeout() {
			return this.allowCoreThreadTimeout;
		}

		public void setAllowCoreThreadTimeout(boolean allowCoreThreadTimeout) {
			this.allowCoreThreadTimeout = allowCoreThreadTimeout;
		}

		public Duration getKeepAlive() {
			return this.keepAlive;
		}

		public void setKeepAlive(Duration keepAlive) {
			this.keepAlive = keepAlive;
		}

	}

	public static class Shutdown {

		/**
		 * Whether the executor should wait for scheduled tasks to complete on shutdown.
		 */
		private boolean awaitTermination;

		/**
		 * Maximum time the executor should wait for remaining tasks to complete.
		 */
		private Duration awaitTerminationPeriod;

		public boolean isAwaitTermination() {
			return this.awaitTermination;
		}

		public void setAwaitTermination(boolean awaitTermination) {
			this.awaitTermination = awaitTermination;
		}

		public Duration getAwaitTerminationPeriod() {
			return this.awaitTerminationPeriod;
		}

		public void setAwaitTerminationPeriod(Duration awaitTerminationPeriod) {
			this.awaitTerminationPeriod = awaitTerminationPeriod;
		}

	}

}

可通过配置文件修改默认配置

# 核心线程数
spring.task.execution.pool.core-size=8  
# 最大线程数
spring.task.execution.pool.max-size=16
# 空闲线程存活时间
spring.task.execution.pool.keep-alive=60s
# 是否允许核心线程超时
spring.task.execution.pool.allow-core-thread-timeout=true
# 线程队列数量
spring.task.execution.pool.queue-capacity=100
# 线程关闭等待
spring.task.execution.shutdown.await-termination=false
spring.task.execution.shutdown.await-termination-period=
# 线程名称前缀
spring.task.execution.thread-name-prefix=task-

2.3、自动配置类

根据官方文档的说明,Spring Boot auto-configures a ThreadPoolTaskExecutor 。最终找到springboot的线程池自动装配类:TaskExecutionAutoConfiguration

@ConditionalOnClass(ThreadPoolTaskExecutor.class)
@Configuration(proxyBeanMethods = false)
// 配置文件绑定器 可以通过这个属性来进行配置当前线程池中的配置
@EnableConfigurationProperties(TaskExecutionProperties.class)
public class TaskExecutionAutoConfiguration {

	/**
	 * Bean name of the application {@link TaskExecutor}.
	 */
	public static final String APPLICATION_TASK_EXECUTOR_BEAN_NAME = "applicationTaskExecutor";
	
    // 自动配置类
	@Bean
    // 没有TaskExecutorBuilder类型的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 })
     // 没有这个类型的bean的时候才会生效
	@ConditionalOnMissingBean(Executor.class)
	public ThreadPoolTaskExecutor applicationTaskExecutor(TaskExecutorBuilder builder) {
		return builder.build();
	}

}

那么看下builder.build()方法

public ThreadPoolTaskExecutor build() {
  return build(ThreadPoolTaskExecutor.class);
}
public <T extends ThreadPoolTaskExecutor> T build(Class<T> taskExecutorClass) {
  // 创建ThreadPoolTaskExecutor实例,然后进行配置
  return configure(BeanUtils.instantiateClass(taskExecutorClass));
}

这里隐藏了一个步骤:在ThreadPoolTaskExecutor的父类ExecutorConfigurationSupport中,有个成员变量:

表示线程拒绝策略:

private RejectedExecutionHandler rejectedExecutionHandler = new ThreadPoolExecutor.AbortPolicy();
public <T extends ThreadPoolTaskExecutor> T configure(T taskExecutor) {
  PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull();
  map.from(this.queueCapacity).to(taskExecutor::setQueueCapacity);
  map.from(this.corePoolSize).to(taskExecutor::setCorePoolSize);
  map.from(this.maxPoolSize).to(taskExecutor::setMaxPoolSize);
  map.from(this.keepAlive).asInt(Duration::getSeconds).to(taskExecutor::setKeepAliveSeconds);
  map.from(this.allowCoreThreadTimeOut).to(taskExecutor::setAllowCoreThreadTimeOut);
  map.from(this.awaitTermination).to(taskExecutor::setWaitForTasksToCompleteOnShutdown);
  map.from(this.awaitTerminationPeriod).as(Duration::toMillis).to(taskExecutor::setAwaitTerminationMillis);
  map.from(this.threadNamePrefix).whenHasText().to(taskExecutor::setThreadNamePrefix);
  map.from(this.taskDecorator).to(taskExecutor::setTaskDecorator);
  if (!CollectionUtils.isEmpty(this.customizers)) {
    this.customizers.forEach((customizer) -> customizer.customize(taskExecutor));
  }
  // 返回对象并给对象中的属性来进行赋值
  return taskExecutor;
}

还有重要的一步:ThreadPoolTaskExecutor间接实现了InitializingBean接口,重写了其中的afterPropertiesSet方法

@Override
public void afterPropertiesSet() {
  initialize();
}

/**
	 * Set up the ExecutorService.
	 */
public void initialize() {
  if (logger.isInfoEnabled()) {
    logger.info("Initializing ExecutorService" + (this.beanName != null ? " '" + this.beanName + "'" : ""));
  }
  if (!this.threadNamePrefixSet && this.beanName != null) {
    setThreadNamePrefix(this.beanName + "-");
  }
  this.executor = initializeExecutor(this.threadFactory, this.rejectedExecutionHandler);
}
@Override
protected ExecutorService initializeExecutor(
  ThreadFactory threadFactory, RejectedExecutionHandler rejectedExecutionHandler) {
  // 创建阻塞队列
  BlockingQueue<Runnable> queue = createQueue(this.queueCapacity);

  ThreadPoolExecutor executor;
  if (this.taskDecorator != null) {
    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);
        }
        // 依然是调用ThreadPoolExecutor中的方法来进行执行的
        super.execute(decorated);
      }
    };
  }
  else {
    executor = new ThreadPoolExecutor(
      this.corePoolSize, this.maxPoolSize, this.keepAliveSeconds, TimeUnit.SECONDS,
      queue, threadFactory, rejectedExecutionHandler);

  }

  if (this.allowCoreThreadTimeOut) {
    executor.allowCoreThreadTimeOut(true);
  }

  this.threadPoolExecutor = executor;
  return executor;
}

2.4、自定义线程池

2.4.1、自定义配置项

import org.springframework.boot.context.properties.ConfigurationProperties;

@ConfigurationProperties(prefix = ExecutorProperties.EXECUTOR_PREFIX)
@Data
public class ExecutorProperties {
    public static final String EXECUTOR_PREFIX = "executor";
    private Integer corePoolSize = 5;
    private Integer maxPoolSize = 10;
    private Integer queueCapacity = 200;
}

2.4.2、自定义线程池类

import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

public class SafelyDestroyExecutor extends ThreadPoolTaskExecutor {
  private static final Logger logger = LoggerFactory.getLogger(SafelyDestroyExecutor.class);

  public SafelyDestroyExecutor() {
  }

  public void destroy() {
    ThreadPoolExecutor threadPoolExecutor = this.getThreadPoolExecutor();
    threadPoolExecutor.shutdown();

    while(!threadPoolExecutor.isTerminated()) {
      try {
        threadPoolExecutor.awaitTermination(50L, TimeUnit.MILLISECONDS);
        logger.warn("CommonSafelyDestroyExecutor is terminating!");
      } catch (InterruptedException var3) {
        logger.error("CommonSafelyDestroyExecutor shutdown is interrupted but ignored!", var3);
      }
    }

    logger.info("CommonSafelyDestroyExecutor is terminated!");
  }
}

2.4.3、配置类

import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor.AbortPolicy;
import java.util.concurrent.atomic.AtomicInteger;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties({ExecutorProperties.class})
public class ExecutorConfig {

    @Bean({"commonSafelyDestroyExecutor"})
    @ConditionalOnClass({SafelyDestroyExecutor.class})
    public SafelyDestroyExecutor safelyDestroyExecutor(ExecutorProperties executorProperties) {
        SafelyDestroyExecutor safelyDestroyExecutor = new SafelyDestroyExecutor();
        safelyDestroyExecutor.setCorePoolSize(executorProperties.getCorePoolSize());
        safelyDestroyExecutor.setMaxPoolSize(executorProperties.getMaxPoolSize());
        safelyDestroyExecutor.setQueueCapacity(executorProperties.getQueueCapacity());
        safelyDestroyExecutor.setRejectedExecutionHandler(new AbortPolicy());
        safelyDestroyExecutor.setThreadFactory(new ThreadFactory() {
            private final String THREAD_PREFIX = "CommonSafelyDestroyExecutor_";
            private final AtomicInteger atomicInteger = new AtomicInteger(1);

            public Thread newThread(Runnable r) {
                return new Thread(r, "CommonSafelyDestroyExecutor_" + this.atomicInteger.getAndIncrement());
            }
        });
        return safelyDestroyExecutor;
    }
}

2.4.4、ExecutorService对外暴露调用接口

为了方便使用当前线程池,对外提供一个service来方便进行使用:

import java.util.Objects;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;

public class ExecutorService {
  private static final Logger logger = LoggerFactory.getLogger(ExecutorService.class);
  @Autowired
  @Qualifier("commonSafelyDestroyExecutor")
  private SafelyDestroyExecutor safelyDestroyExecutor;

  public ExecutorService() {
  }

  public <V> Future<V> asyncExecution(Callable<V> task) throws ServiceException {
    try {
      return this.safelyDestroyExecutor.submit((Callable)Objects.requireNonNull(task));
    } catch (Exception var3) {
      logger.error("异步执行异常", var3);
      throw ServiceExceptions.S004.buildServiceException("异步执行异常", var3);
    }
  }

  public <T> T getFutureResult(Future<T> future) throws ServiceException {
    try {
      return ((Future)Objects.requireNonNull(future)).get();
    } catch (ExecutionException var4) {
      if (var4.getCause() != null) {
        Throwable t = var4.getCause();
        logger.error("获取future中结果失败", t);
        throw ServiceExceptions.S001.buildServiceException(!StringUtil.isBlank(t.getMessage()) ? t.getMessage() : "获取future中结果失败", t);
      } else {
        logger.error("获取future中结果失败", var4);
        throw ServiceExceptions.S001.buildServiceException(!StringUtil.isBlank(var4.getMessage()) ? var4.getMessage() : "获取future中结果失败", var4);
      }
    } catch (Exception var5) {
      logger.error("获取future中结果失败", var5);
      throw ServiceExceptions.S001.buildServiceException(!StringUtil.isBlank(var5.getMessage()) ? var5.getMessage() : "获取future中结果失败", var5);
    }
  }
}

配置到配置类中去

@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties({ExecutorProperties.class})
public class ExecutorConfig {

    @Bean({"commonSafelyDestroyExecutor"})
    @ConditionalOnClass({SafelyDestroyExecutor.class})
    public SafelyDestroyExecutor safelyDestroyExecutor(ExecutorProperties executorProperties) {
        SafelyDestroyExecutor safelyDestroyExecutor = new SafelyDestroyExecutor();
        safelyDestroyExecutor.setCorePoolSize(executorProperties.getCorePoolSize());
        safelyDestroyExecutor.setMaxPoolSize(executorProperties.getMaxPoolSize());
        safelyDestroyExecutor.setQueueCapacity(executorProperties.getQueueCapacity());
        safelyDestroyExecutor.setRejectedExecutionHandler(new AbortPolicy());
        safelyDestroyExecutor.setThreadFactory(new ThreadFactory() {
            private final String THREAD_PREFIX = "CommonSafelyDestroyExecutor_";
            private final AtomicInteger atomicInteger = new AtomicInteger(1);

            public Thread newThread(Runnable r) {
                return new Thread(r, "CommonSafelyDestroyExecutor_" + this.atomicInteger.getAndIncrement());
            }
        });
        return safelyDestroyExecutor;
    }

    @Bean
    @ConditionalOnClass({ExecutorService.class})
    @ConditionalOnBean(
        value = {SafelyDestroyExecutor.class},
        name = {"commonSafelyDestroyExecutor"}
    )
    public ExecutorService executorService() {
        return new ExecutorService();
    }
}

三、总结

总结@Async可能失效的原因

1、@SpringBootApplication启动类当中没有添加@EnableAsync注解。
2、异步方法使用注解@Async的返回值只能为void或者Future。
3、没有走Spring的代理类。因为@Transactional和@Async注解的实现都是基于Spring的AOP,而AOP的实现是基于动态代理模式实现的。那么注解失效的原因就很明显了,有可能因为调用方法的是对象本身而不是代理对象,因为没有经过Spring容器管理。
解决方法:
这里具体说一下第三种情况的解决方法。
1、注解的方法必须是public方法。

2、注解的方法不要定义为static
3、方法一定要从另一个类中调用,也就是从类的外部调用,类的内部调用是无效的。
4、如果需要从类的内部调用,需要先获取其代理类。

posted @ 2023-04-18 09:55  雩娄的木子  阅读(361)  评论(0编辑  收藏  举报