如上图所示,自定义线程池存在三种方式,其中前两种都是修改springboot 的默认线程池,第三种为完全的自定义线程池。
一. 修改默认线程池
1.1 修改默认线程池配置
如果没有配置线程池的话,springboot会自动配置一个ThreadPoolTaskExecutor 线程池到bean当中。 按如下配置,可修改默认线程池
# 核心线程数
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=10
# 线程名称前缀
spring.task.execution.thread-name-prefix=custom-task-
1.2 自定义配置+实现spring默认线程池装配类+async注解
1.2.1 自定义配置
1. 修改application.properties
task.pool.corePoolSize=20
task.pool.maxPoolSize=40
task.pool.keepAliveSeconds=300
task.pool.queueCapacity=50
2. 配置类
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* 线程池配置属性类
* Created by Fant.J.
*/
@ConfigurationProperties(prefix = "task.pool")
public class TaskThreadPoolConfig {
private int corePoolSize;
private int maxPoolSize;
private int keepAliveSeconds;
private int queueCapacity;
...getter and setter methods...
}
1.2.2 实现默认线程池装配类
/**
* 原生(Spring)异步任务线程池装配类
* Created by Fant.J.
*/
@Slf4j
@Configuration
public class NativeAsyncTaskExecutePool implements AsyncConfigurer{
//注入配置类
@Autowired
TaskThreadPoolConfig config;
@Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
//核心线程池大小
executor.setCorePoolSize(config.getCorePoolSize());
//最大线程数
executor.setMaxPoolSize(config.getMaxPoolSize());
//队列容量
executor.setQueueCapacity(config.getQueueCapacity());
//活跃时间
executor.setKeepAliveSeconds(config.getKeepAliveSeconds());
//线程名字前缀
executor.setThreadNamePrefix("MyExecutor-");
// setRejectedExecutionHandler:当pool已经达到max size的时候,如何处理新任务
// CallerRunsPolicy:不在新线程中执行任务,而是由调用者所在的线程来执行
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.initialize();
return executor;
}
/**
* 异步任务中异常处理
* @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());
}
};
}
}
1.2.3 @Async 使用线程池
@Component
public class AsyncTask {
protected final Logger logger = LoggerFactory.getLogger(this.getClass());
@Async
public void doTask2(int i) throws InterruptedException{
logger.info("Task2-Native"+i+" started.");
}
}
二. 自定义线程池
2.1 自定义配置
1. 修改application.properties
task.pool.corePoolSize=20
task.pool.maxPoolSize=40
task.pool.keepAliveSeconds=300
task.pool.queueCapacity=50
2. 配置类
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* 线程池配置属性类
* Created by Fant.J.
*/
@ConfigurationProperties(prefix = "task.pool")
public class TaskThreadPoolConfig {
private int corePoolSize;
private int maxPoolSize;
private int keepAliveSeconds;
private int queueCapacity;
...getter and setter methods...
}
2.2 自定义线程池
/**
* 创建线程池
* Created by Fant.J.
*/
@Configuration
@EnableAsync
public class TaskExecutePool {
@Autowired
private TaskThreadPoolConfig config;
@Bean
public Executor myTaskAsyncPool() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
//核心线程池大小
executor.setCorePoolSize(config.getCorePoolSize());
//最大线程数
executor.setMaxPoolSize(config.getMaxPoolSize());
//队列容量
executor.setQueueCapacity(config.getQueueCapacity());
//活跃时间
executor.setKeepAliveSeconds(config.getKeepAliveSeconds());
//线程名字前缀
executor.setThreadNamePrefix("MyExecutor-");
// setRejectedExecutionHandler:当pool已经达到max size的时候,如何处理新任务
// CallerRunsPolicy:不在新线程中执行任务,而是由调用者所在的线程来执行
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.initialize();
return executor;
}
}
2.3 修改启动类
给启动类添加注解
@EnableAsync
@EnableConfigurationProperties({TaskThreadPoolConfig.class} ) // 开启配置属性支持
2.4 使用自定义线程池
@Async + 线程池名
/**
* Created by Fant.J.
*/
@Component
public class AsyncTask {
protected final Logger logger = LoggerFactory.getLogger(this.getClass());
//myTaskAsynPool即配置线程池的方法名,此处如果不写自定义线程池的方法名,会使用默认的线程池
@Async("myTaskAsyncPool")
public void doTask1(int i) throws InterruptedException{
logger.info("Task"+i+" started.");
}
}
3. 验证
那么如何验证当前线程池信息,确认自定义线程池是成功的呢?
参考:blog.51cto.com/u_16213424/…
4. 线程池配置准则
线程池配置分两种场景,一是cpu计算密集型,而是io密集型
4.1 计算密集型
n=cpu核心数
核心线程数=n+1
最大线程数=2n
4.2 io 密集型
n=cpu核心数
核心线程数=2n
最大线程数=4n