@Configuration
@EnableAsync // 开启异步注解@Async
@Slf4j
public class ExecutorConfig {
@Value("${async.executor.thread.core_pool_size:10}")
private int corePoolSize;
@Value("${async.executor.thread.max_pool_size:15}")
private int maxPoolSize;
@Value("${async.executor.thread.queue_capacity:9999}")
private int queueCapacity;
@Value("${async.executor.thread.name.prefix:async_task_}")
private String namePrefix;
@Bean(name = "asyncServiceExecutor")
public Executor asyncServiceExecutor() {
log.info("start asyncServiceExecutor");
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
//配置核心线程数
executor.setCorePoolSize(corePoolSize);
//配置最大线程数
executor.setMaxPoolSize(maxPoolSize);
//配置队列大小
executor.setQueueCapacity(queueCapacity);
//配置线程池中的线程的名称前缀
executor.setThreadNamePrefix(namePrefix);
// rejection-policy:当pool已经达到max size的时候,如何处理新任务
// CALLER_RUNS:不在新线程中执行任务,而是有调用者所在的线程来执行
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
//执行初始化
executor.initialize();
return executor;
}
}
@Component
@Slf4j
public class DemoService {
@Async("asyncServiceExecutor")
public void test() {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.info("异步任务开始执行");
}
}
单测:
import lombok.extern.slf4j.Slf4j;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
@Slf4j
@RunWith(SpringRunner.class)
@SpringBootTest(classes = App.class)
public class BaseTest {
}
@Slf4j
public class DemoServiceTest extends BaseTest {
@Autowired
DemoService demoService;
@Test
public void test() {
for (int i = 0; i < 10; i++) {
demoService.test();
log.info(" 主线程继续执行");
}
log.info(" 主线程继续执行");
}
}
监控线程池信息模式,可以考虑在队列大小大于容量的2/3时打印告警日志等:
方式一:
@Configuration
@EnableAsync // 开启异步注解@Async
@Slf4j
public class ExecutorConfig {
@Value("${async.executor.thread.core_pool_size:5}")
private int corePoolSize;
@Value("${async.executor.thread.max_pool_size:8}")
private int maxPoolSize;
@Value("${async.executor.thread.queue_capacity:4}")
private int queueCapacity;
@Value("${async.executor.thread.name.prefix:async_task_}")
private String namePrefix;
@Bean(name = "asyncServiceExecutor")
public Executor asyncServiceExecutor() {
log.info("start asyncServiceExecutor");
ThreadPoolTaskExecutor executor = new VisiableThreadPoolTaskExecutor();
//配置核心线程数
executor.setCorePoolSize(corePoolSize);
//配置最大线程数
executor.setMaxPoolSize(maxPoolSize);
//配置队列大小
executor.setQueueCapacity(queueCapacity);
//配置线程池中的线程的名称前缀
executor.setThreadNamePrefix(namePrefix);
// rejection-policy:当pool已经达到max size的时候,如何处理新任务
// CALLER_RUNS:不在新线程中执行任务,而是有调用者所在的线程来执行
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
//执行初始化
executor.initialize();
return executor;
}
}
@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);
}
}
方式二:
@Slf4j
@Component
public class MonitorThreadPool {
@PostConstruct
public void init() {
ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1);
scheduledExecutorService.scheduleAtFixedRate(() -> {
log.info("MonitorThreadPool 线程池队列监控开始");
// 有多个异步线程池可以新建一个枚举,定义线程池bean名称,然后循环迭代
log.info("asyncServiceExecutor线程池队列堵塞:{}", getThreadPoolInfo());
log.info("ThreadPoolFactory 线程池队列监控结束");
}, 4L, 5L, TimeUnit.SECONDS);
}
private int getThreadPoolInfo() {
ThreadPoolTaskExecutor threadPoolTaskExecutor = (ThreadPoolTaskExecutor) ApplicationContextUtil.getBean("asyncServiceExecutor");
return threadPoolTaskExecutor.getThreadPoolExecutor().getQueue().size();
}
}