目录
一、代码部分
AsyncConfig
import com.tmzh.saas.topic.properties.ThreadPoolProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;
@EnableAsync
@Configuration
public class AsyncConfig {
@Bean(name = "myTaskExecutor")
public Executor tmyTaskExecutor(ThreadPoolProperties threadPoolProperties) {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
//核心线程数量,线程池创建时候初始化的线程数
executor.setCorePoolSize(threadPoolProperties.getCorePoolSize());
//最大线程数,只有在缓冲队列满了之后才会申请超过核心线程数的线程
executor.setMaxPoolSize(threadPoolProperties.getMaxPoolSize());
//缓冲队列,用来缓冲执行任务的队列
executor.setQueueCapacity(threadPoolProperties.getQueueCapacity());
//当超过了核心线程出之外的线程在空闲时间到达之后会被销毁
executor.setKeepAliveSeconds(threadPoolProperties.getKeepAliveTime());
//设置好了之后可以方便我们定位处理任务所在的线程池
executor.setThreadNamePrefix(threadPoolProperties.getThreadNamePrefix());
//用来设置线程池关闭的时候等待所有任务都完成再继续销毁其他的Bean
executor.setWaitForTasksToCompleteOnShutdown(true);
//该方法用来设置线程池中任务的等待时间,如果超过这个时候还没有销毁就强制销毁,以确保应用最后能够被关闭,而不是阻塞住。
executor.setAwaitTerminationSeconds(60);
//线程池对拒绝任务的处理策略:这里采用了CallerRunsPolicy策略,当线程池没有处理能力的时候,该策略会直接在 execute 方法的调用线程中运行被拒绝的任务;如果执行程序已关闭,则会丢弃该任务
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
// 初始化
// 通过spring @Bean方式注入ThreadPoolTaskExecutor实例时,可以不需要这一步。
// 由于ThreadPoolTaskExecutor继承了ExecutorConfigurationSupport,初始化对象时会调用ExecutorConfigurationSupport.afterPropertiesSet()
executor.initialize();
return executor;
}
}
ThreadPoolProperties
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
@Data
@Configuration
@ConfigurationProperties(prefix = "thread.pool")
public class ThreadPoolProperties {
/**
* 核心线程数(默认线程数)
*/
private int corePoolSize = Runtime.getRuntime().availableProcessors();
/**
* 最大线程数
*/
private int maxPoolSize = Runtime.getRuntime().availableProcessors();
/**
* 允许线程空闲时间(单位:默认为秒)
*/
private int keepAliveTime = 60;
/**
* 缓冲队列大小
*/
private int queueCapacity = 200;
/**
* 线程池名前缀
*/
private String threadNamePrefix = "asyncTask-";
}
application.yml
thread:
pool:
core-pool-size: 8
max-pool-size: 16
keep-alive-time: 60
queue-capacity: 1000
thread-name-prefix: myAsyncTask-
META-INF/additional-spring-configuration-metadata.json
{
"properties": [
{
"name": "thread.pool.core-pool-size",
"type": "java.lang.Integer",
"description": "核心线程数"
},
{
"name": "thread.pool.max-pool-size",
"type": "java.lang.Integer",
"description": "最大线程数"
},
{
"name": "thread.pool.keep-alive-time",
"type": "java.lang.Integer",
"description": "允许线程空闲时间(单位:默认为秒)"
},
{
"name": "thread.pool.queue-capacity",
"type": "java.lang.Integer",
"description": "缓冲队列大小"
},
{
"name": "thread.pool.thread-name-prefix",
"type": "java.lang.String",
"description": "线程池名前缀"
}
]
}
二、如何确定线程池大小?
Ncpu 表示 核心数。
如果是CPU密集型任务,就需要尽量压榨CPU,参考值可以设为 Ncpu+1
如果是IO密集型任务,参考值可以设置为 2 * Ncpu