package com.xx.config;
import lombok.extern.slf4j.Slf4j;
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 org.springframework.util.concurrent.ListenableFuture;
import java.util.concurrent.Callable;
import java.util.concurrent.Executor;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadPoolExecutor;
/**
* @author xingxia2
* @date 2021-12-10 09:27:35
* @description: 线程池配置
* 一.
* 1.tasks:并发量,例如为500-1000
* 2.taskCost:每个任务花费时间,例如为0.1s
* 3.responseTime:最大容忍时间,例如为1s
* 二.
* corePoolSize = tasks * taskCost = (500-1000) * 0.1 = 50-100 那么corePoolSize应该大于50,按照8020原则,corePoolSize设置为80即可
* queueCapacity = (coreSizePool / taskCost) * responseTime = 80 / 0.1 * 1 = 800
* maxPoolSize = (max(tasks) - queueCapacity) / (1 / taskCost) = (1000-800)/10 = 20
*
*
* 注:计算方式多种多样
*
*
*/
@Slf4j
@EnableAsync
@Configuration
public class ExecutorConfig {
/**
* Excel导出线程池
* @return Executor
*/
@Bean(name = "asyncExcelExecutor")
public Executor asyncExcelExecutor() {
return createThreadPoolExecutor(5, 10, 20, 2, "async-service-excel");
}
/**
* 日志收集线程池
* @return Executor
*/
@Bean(name = "asyncLogExecutor")
public Executor asyncLogExecutor() {
return createThreadPoolExecutor(10, 20, 0, 2, "async-service-log");
}
/**
* 离线任务线程池
*/
public static Executor offlineTaskExecutor = createThreadPoolExecutor(10, 20, 0, 2, "async-service-offline");
/**
* 线程池创建工具
* @param corePoolSize 核心线程数
* @param maxPoolSize 最大线程数
* @param keepAliveSeconds 线程最大存活时间
* @param queueSize 队列大小
* @param threadName 现场名称前缀
* @return Executor
*/
private static Executor createThreadPoolExecutor(Integer corePoolSize, Integer maxPoolSize, Integer keepAliveSeconds, Integer queueSize, String threadName) {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor() {
private void showThreadPoolInfo() {
ThreadPoolExecutor threadPoolExecutor = getThreadPoolExecutor();
log.info("{},执行总任务数 [{}], 已经完成任务数 [{}], 正在执行任务数 [{}], 队列等待任务数 [{}], 当前线程池中线程数 [{}], 最大线程数 [{}], 核心线程数 [{}]",
this.getThreadNamePrefix(),
threadPoolExecutor.getTaskCount(),
threadPoolExecutor.getCompletedTaskCount(),
threadPoolExecutor.getActiveCount(),
threadPoolExecutor.getQueue().size(),
threadPoolExecutor.getPoolSize(),
threadPoolExecutor.getMaximumPoolSize(),
threadPoolExecutor.getCorePoolSize());
}
@Override
public void execute(Runnable task) {
showThreadPoolInfo();
super.execute(task);
}
@Override
public void execute(Runnable task, long startTimeout) {
showThreadPoolInfo();
super.execute(task, startTimeout);
}
@Override
public Future<?> submit(Runnable task) {
showThreadPoolInfo();
return super.submit(task);
}
@Override
public <T> Future<T> submit(Callable<T> task) {
showThreadPoolInfo();
return super.submit(task);
}
@Override
public ListenableFuture<?> submitListenable(Runnable task) {
showThreadPoolInfo();
return super.submitListenable(task);
}
@Override
public <T> ListenableFuture<T> submitListenable(Callable<T> task) {
showThreadPoolInfo();
return super.submitListenable(task);
}
};
// 核心线程数
executor.setCorePoolSize(corePoolSize);
// 最大线程数
executor.setMaxPoolSize(maxPoolSize);
// 线程最大存活时间(如果当前线程数>核心线程数,则会kill一些线程)
executor.setKeepAliveSeconds(keepAliveSeconds);
// 配置队列大小
executor.setQueueCapacity(queueSize);
// 配置线程池中的线程名称前缀
executor.setThreadNamePrefix(threadName);
// 线程池饱和策略,AbortPolicy:直接拒绝,并抛出异常RejectedExecutionException;CallerRunsPolicy:不在新线程中执行任务,调用所有者所在线程执行;DiscardPolicy:将任务删除;DiscardOldestPolicy:删除工作队列头部任务
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardOldestPolicy());
// 初始化
executor.initialize();
return executor;
}
}
@Async("asyncExcelExecutor")
public void export() {
log.info("开始执行异步导出任务...");
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.info("异步导出任务结束...");
}
部分线程池参数设置方式参考(具体还是得看现场cpu负载):
https://www.cnblogs.com/owenma/p/8557074.html