在开发springboot应用服务时,不可避免的要用到异步任务和线程池。springboot的线程池是可以自定义的,所以我们经常在项目中看到类似下面的代码@BeanpublicExecutortaskExecutor(){executor.setCorePoolSize(config.getCorePoolSize());executor.setMaxPoolSize(config.getMaxPoolSize());executor.setQueueCapacity(config.getQueueCapacity());executor.setThreadNamePrefix("TaskExecutePool-");executor.setRejectedExecutionHandler(newThreadPoolExecutor.CallerRunsPolicy());真的);executor.initialize();returnexecutor;}使用起来很方便,但是这样做有几个问题:开发者在代码中随意定义线程池,开发者A自定义一个线程池,开发者B自定义一个线程池。线程池资源的使用没有计划和合理安排,会增加后期维护的成本。一旦发现线程池数量不足或资源满载,很难调整配置。只能调整代码,重新部署。很多人写代码,很难统计服务中的线程池,有多少个线程池。如果不跟踪代码,就很难知道它是如何被使用的。定义了50个线程,有没有资源浪费?有资源等待吗?为了解决以上问题,我开发了一个SpringBootStarter(开源项目地址:https://gitee.com/hanxt/zimug...),方便集成到SpringBoot项目中。目标是在不改变SpringBoot线程池核心实现的情况下,使其可视化、易于观察、易于配置、易于使用。需要注意的是,zimug-monitor-threadpool并没有改变SpringBoot线程池的实现,只是增加了初始化阶段的自动配置加载和运行时的状态监控。所以任何关于SpringBoot线程池运行时性能的讨论都与本文及其实现无关。1.易于集成和配置。通过上述项目地址获取源码,然后用maven编译安装本地m2仓库。然后引入com.zimugzimug-monitor-threadpool1.0配置springbootYAML如下(application.yml),配置了两个线程池,分别是test和test2。当thread-pool.enable=true时,线程池配置生效。thread-pool:enable:truepoolLists:-poolId:test#线程池的唯一标识poolName:Test1#线程池的中文描述,比如线程池是给谁用的?coreSize:5#线程池初始化核心线程数maxSize:10#线程池最大线程容量queueCapacity:10#线程池等待队列容量-poolId:test2poolName:test2coreSize:5maxSize:10queueCapacity:10通过下面张图了解以上配置信息。当线程任务的core_size被活动任务线程占满后,线程任务会被放入等待队列(queueCapacity=10)。当等待队列queueCapacity也被占满时,线程池的容量就会扩大。线程池的容量最大可以扩展到maxSize。如果maxSize和queueCapacity都已满,则任务被阻塞。2.简单易用使用方法同SpringBoot代码方法自定义线程池。@Async注解的值为test,调用该注解标识的函数会在上面配置的测试线程池中执行。@ComponentpublicclassTestTask{@Async("test")//这里注意,test是线程池配置的poolIdpublicFuturetest()throwsException{System.out.println("当前线程:"+Thread.currentThread().getName());returnnewAsyncResult<>("测试任务");}}3.可视化,方便观察在项目中引入zimug-monitor-threadpool后,配置线程池,使用线程池。访问服务的/pool.html,获取当前SpringBoot服务的线程池配置信息和运行状态信息。线程池ID、描述、初始化线程数、最大线程数、任务等待队列容量为上面yaml静态配置的当前线程池的容量,即:线程池当前线程数(活跃线程数+非活跃线程数之和)当前活跃线程数,即正在运行程序任务的线程数线程池中活跃线程的最大峰值。如果这个值等于初始化的线程数,说明已经有任务在等待,即任务被放入等待队列,效率较低。如果该值大于初始化线程数,则说明任务等待队列已满,需要扩容。如果该值接近等于最大线程数,则需要增加最大线程数的值。当前任务等待队列的剩余容量。剩余容量越少,等待执行的任务就越多。4.实现原理zimug-monitor-threadpool的实现原理也很简单。简单说一下原理,具体实现参考源码。首先通过SpringBoot加载yaml配置信息,配置加载完成后自动加载配置。这个实现原理和实现方法网上到处都是,就不写了。配置信息加载完成后,会创建一个新的ThreadPoolTask??Executor对象,并通过Spring的ConfigurableBeanFactory将线程池对象的bean注册到Spring上下文中。bean的id是poolId配置。它可以被运行时任务使用。configurableBeanFactory.registerSingleton(pool.getPoolId(),taskExecutor);当需要监控线程池运行时状态时,通过getBean方法获取线程池对象,从而获取运行时信息返回给前台请求。ThreadPoolTask??ExecutormemThreadPool=(ThreadPoolTask??Executor)applicationContext.getBean(poolModel.getPoolId());欢迎关注我的公告号:字母哥杂谈,回复003赠送本文所在专栏《docker修炼之道》的PDF版,以及30多篇docker优质文章。Antetokounmpo博客:zimug.com