Spring Boot线程池简单封装(执行任务时获取线程池状态)

今天来分享一下使用Spring Boot线程池,并且在每次执行任务的时候打印线程池的状态日志

Spring Boot线程池的基本用法

主要分为以下几个步骤:

开启异步线程

在项目入口加上注解@EnableAsync

@SpringBootApplication
@EnableAsync // 增加该注解
public class RootCauseInferenceServiceApplication {

    public static ApplicationContext applicationContext;

    public static void main(String[] args) {
        applicationContext = SpringApplication.run(RootCauseInferenceServiceApplication.class, args);
    }
}

线程池参数配置

@Configuration
public class AsyncScheduledTaskConfig {

    // 核心线程池大小
    public static int corePoolSize = 10;

    // 最大可创建的线程数
    // @Value("${async.executor.thread.max_pool_size}")
    private int maxPoolSize = 10;

    // 队列最大长度
    // @Value("${async.executor.thread.queue_capacity}")
    private int queueCapacity = 10;

    // 线程池维护线程所允许的空闲时间
    // @Value("${async.executor.thread.keep_alive_seconds}")
    private int keepAliveSeconds = 300;

    // 线程池名前缀
    // @Value("${async.executor.thread.threadNamePrefix}")
    private static final String threadNamePrefix = "Async-Service-";

    @Bean(name = "threadPoolTaskExecutor")
    public ThreadPoolTaskExecutor threadPoolTaskExecutor() {
        ThreadPoolTaskExecutor executor = new MyExecutor(); // 继承ThreadPoolTaskExecutor自定义的线程池 
        executor.setMaxPoolSize(maxPoolSize);
        executor.setCorePoolSize(corePoolSize);
        executor.setQueueCapacity(queueCapacity);
        executor.setKeepAliveSeconds(keepAliveSeconds);
        executor.setThreadNamePrefix(threadNamePrefix);
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy()); // 拒绝策略
        // 初始化
        executor.initialize();
        return executor;
    }
}

定义任务

@Service
public class AsyncService {

    @Async("threadPoolTaskExecutor") // 使用该注解,会从线程池取线程异步执行该方法
    public void runTask() {
    	// 具体任务
    }
}

执行任务

@Service
public class InferenceService {

    @Resource
    private AsyncService asyncService;

    public InferenceDto inference() {
        for (int i = 0; i < 10; i++) {
            asyncService.runTask(); // 调用执行任务,此处要注意runTask不能与调用方在同一个类里面
        }
        return new InferenceDto();
    }

}

以上就是使用Spring Boot线程池的基本步骤,但是我们无法监控到线程池的运行状态;下面是使用面向切面编程的方式在每次执行任务时打印线程池的状态日志

自定义线程池

@Slf4j
public class MyExecutor extends ThreadPoolTaskExecutor { // 继承ThreadPoolTaskExecutor 

    public void showThreadPoolInfo() { // 打印线程池的状态日志
        ThreadPoolExecutor threadPoolExecutor = getThreadPoolExecutor();
        log.info("taskCount [{}], completedTaskCount [{}], activeCount [{}], queueSize [{}]",
            threadPoolExecutor.getTaskCount(), threadPoolExecutor.getCompletedTaskCount(),
            threadPoolExecutor.getActiveCount(), threadPoolExecutor.getQueue().size());
    }

    @Override
    public <T> Future<T> submit(Callable<T> task) { // 重写submit方法,实际上什么也没有干,但是必须重写,否则无法实现面向切面编程
        return super.submit(task);
    }
}

定义切面

@Aspect
@Component
public class ExecutorAspect {
	// 在线程池执行submit方法时打印线程池的状态
    @Before("execution(* com.janson.rootcauseinferenceservice.executor.MyExecutor.submit(..))")
    public void showThreadPoolInfo() {
        MyExecutor myExecutor =
            (MyExecutor) RootCauseInferenceServiceApplication.applicationContext.getBean("threadPoolTaskExecutor"); // 获取到线程池的Bean对象
        myExecutor.showThreadPoolInfo();
    }
}

那么问题来了,为什么不直接在重写submit方法内部打印线程池的状态呢?
因为我还没有深入了解,线程池是不是只会调用这个submit方法,如果是调用其他方法,我们要在每个submit/execute方法里面都调用一次showThreadPoolInfo()方法吗?!

后续可以深入研究一下线程池实现原理~

参考资料

springboot线程池的使用和扩展

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值