线程池配置
@Configuration
@EnableAsync
@Slf4j
public class ThreadPoolConfig {
@Value("${async.executor.thread.core_pool_size}")
private int corePoolSize;
@Value("${async.executor.thread.max_pool_size}")
private int maxPoolSize;
@Value("${async.executor.thread.queue_capacity}")
private int queueCapacity;
@Value("${async.executor.thread.name.prefix}")
private String namePrefix;
/**
* IO密集型任务 = 一般为2*CPU核心数(常出现于线程中:数据库数据交互、文件上传下载、网络数据传输等等)
* CPU密集型任务 = 一般为CPU核心数+1(常出现于线程中:复杂算法)
* 混合型任务 = 视机器配置和复杂度自测而定
*/
@Bean(name = "asyncTaskExecutor")
public ThreadPoolTaskExecutor asyncTaskExecutor() {
// ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
ThreadPoolTaskExecutor executor = new VisiableThreadPoolTaskExecutor();
//1: 核心线程数目
executor.setCorePoolSize(corePoolSize);
//2: 指定最大线程数,只有在缓冲队列满了之后才会申请超过核心线程数的线程
executor.setMaxPoolSize(maxPoolSize);
//3: 队列中最大的数目
executor.setQueueCapacity(queueCapacity);
//4: 线程名称前缀
executor.setThreadNamePrefix(namePrefix);
//5:当pool已经达到max size的时候,如何处理新任务
// CallerRunsPolicy: 会在execute 方法的调用线程中运行被拒绝的任务,如果执行程序已关闭,则会丢弃该任务
// AbortPolicy: 抛出java.util.concurrent.RejectedExecutionException异常
// DiscardOldestPolicy: 抛弃旧的任务
// DiscardPolicy: 抛弃当前的任务
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
//6: 线程空闲后的最大存活时间(默认值 60),当超过了核心线程出之外的线程在空闲时间到达之后会被销毁
executor.setKeepAliveSeconds(60);
//7:线程空闲时间,当线程空闲时间达到keepAliveSeconds(秒)时,线程会退出,直到线程数量等于corePoolSize,如果allowCoreThreadTimeout=true,则会直到线程数量等于0
executor.setAllowCoreThreadTimeOut(false);
executor.initialize();
return executor;
}
}
application.yml的配置
# 异步线程配置
# 配置核心线程数
async.executor.thread.core_pool_size : 5
# 配置最大线程数
async.executor.thread.max_pool_size : 5
# 配置队列大小
async.executor.thread.queue_capacity : 99999
# 配置线程池中的线程的名称前缀
async.executor.thread.name.prefix : hhh-Thread-
调用时在方法添加注解 @Async(“asyncTaskExecutor”)
@Async("asyncTaskExecutor")
public void getUserInfo() {
log.info("===== start =====");
long st = System.currentTimeMillis();
try {
Thread.sleep(500);
} catch (Exception exception) {
log.error("exception:{}", exception.getMessage());
}
log.info("===== end ===== {} ms", (System.currentTimeMillis() - st));
}
创建了一个ThreadPoolTaskExecutor的子类,在每次提交线程的时候都会将当前线程池的运行状况打印出来
将配置类ThreadPoolConfig 中
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor()
修改成
ThreadPoolTaskExecutor executor = new VisiableThreadPoolTaskExecutor();
package com.company.project.config;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.util.concurrent.ListenableFuture;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadPoolExecutor;
@Slf4j
public class VisiableThreadPoolTaskExecutor extends ThreadPoolTaskExecutor {
private void showThreadPoolInfo(String prefix) {
ThreadPoolExecutor threadPoolExecutor = getThreadPoolExecutor();
if (null == threadPoolExecutor) {
return;
}
log.info("{}, {},taskCount [{}], completedTaskCount [{}], activeCount [{}], queueSize [{}]",
this.getThreadNamePrefix(),
prefix,
threadPoolExecutor.getTaskCount(),
threadPoolExecutor.getCompletedTaskCount(),
threadPoolExecutor.getActiveCount(),
threadPoolExecutor.getQueue().size());
}
@Override
public void execute(Runnable task) {
showThreadPoolInfo("1. do execute");
super.execute(task);
}
@Override
public void execute(Runnable task, long startTimeout) {
showThreadPoolInfo("2. do execute");
super.execute(task, startTimeout);
}
@Override
public Future<?> submit(Runnable task) {
showThreadPoolInfo("1. do submit");
return super.submit(task);
}
@Override
public <T> Future<T> submit(Callable<T> task) {
showThreadPoolInfo("2. do submit");
return super.submit(task);
}
@Override
public ListenableFuture<?> submitListenable(Runnable task) {
showThreadPoolInfo("1. do submitListenable");
return super.submitListenable(task);
}
@Override
public <T> ListenableFuture<T> submitListenable(Callable<T> task) {
showThreadPoolInfo("2. do submitListenable");
return super.submitListenable(task);
}
}
showThreadPoolInfo方法中将任务总数、已完成数、活跃线程数,队列大小都打印出来了,然后Override了父类的execute、submit等方法,在里面调用showThreadPoolInfo方法,这样每次有任务被提交到线程池的时候,都会将当前线程池的基本情况打印到日志中