[1.1 核心需求](#1.1 核心需求)
[1.2 架构总览](#1.2 架构总览)
[1.3 核心原理](#1.3 核心原理)
[1.4 参数动态性总结表](#1.4 参数动态性总结表)
前言
线程池(Thread Pool),是一种基于池化思想管理线程的工具,用于降低资源消耗、提高响应速度、提高线程的管理性。池化技术的引入,可以有效的减少线程频繁申请/销毁和调度所带来的额外开销。
在分布式、高并发的现代Java应用中,线程池是承载业务逻辑、实现异步处理的基石。然而,传统的线程池(如 ThreadPoolExecutor)在使用中存在一个普遍痛点:其核心参数(如核心线程数、最大线程数)在初始化后就固定不变了。
这导致我们在面对突发流量、任务特性变化时非常被动:
流量突增:队列迅速堆积,任务拒绝,影响用户体验。
流量低谷:核心线程持续空闲,造成资源浪费。
参数调整:需要修改配置、重启应用,运维成本高,风险大。
在实际的工作中,线程池使用的场景非常多,但线程池的参数并不好一次就配置好,同时需要做监控处理,知道整个线程的消耗情况。根据IO密集型,CPU密集型不通过的任务差异,做压测验证调整。
因此,一个能够实时监控、动态调整参数的线程池组件,成为了提升应用弹性和可观测性的关键。本文将带领大家,从需求分析开始,一步步搭建一个功能完整的动态线程池组件。
一、动态线程池需求分析与原理
1.1 核心需求
我们的动态线程池组件需要实现以下核心目标:
无侵入集成:业务方通过简单的注解或配置即可接入,无需大幅修改代码。
实时监控:采集并展示线程池的实时运行状态,包括:活跃线程数、队列大小、任务完成数、拒绝策略触发次数等。
动态调参:在应用不重启的情况下,通过管理界面动态修改核心参数(核心线程数、最大线程数、存活时间等)。
通知告警:当线程池负载过高(如队列容量超过阈值)或触发拒绝策略时,能及时发出告警。
可视化管理:提供一个友好的Web界面,用于查看所有应用的线程池状态和进行参数调整。
1.2 架构总览
组件整体分为三部分:
SDK(客户端):集成到业务应用中,负责包装原生线程池、采集数据、与注册中心通信。
注册中心(Redis):作为轻量级的中心节点,用于SDK上报数据和管理端下发指令。
管理端(Admin UI):提供Web界面和API,用于数据展示和参数修改。
数据流:SDK -> 上报数据 -> Redis <- 管理端拉取/订阅 <- 用户操作UI -> 下发指令 -> Redis -> SDK订阅并执行。
1.3 核心原理
核心思路是包装原生ThreadPoolExecutor,在其执行任务的同时,采集运行数据。
采集到数据后,需要定期上报到注册中心(Redis),供管理端前端页面拉取。
Redis实现订阅发布消息,变更线程池,这是实现"动态"的关键。当用户在管理端修改参数后,通过Redis的发布订阅模式通知SDK。
1.4 参数动态性总结表
| 参数 | 动态修改 | 原生支持 | 注意事项 |
|---|---|---|---|
| 核心线程数 | ✅ | ✅ | 需保证 ≤ 最大线程数 |
| 最大线程数 | ✅ | ✅ | 需保证 ≥ 核心线程数 |
| 线程存活时间 | ✅ | ✅ | 对已有线程延迟生效 |
| 允许核心线程超时 | ✅ | ✅ | 默认关闭 |
| 队列容量 | ⚠️ | ❌ | 需自定义队列实现 |
| 队列类型 | ❌ | ❌ | 必须重启 |
| 线程工厂 | ❌ | ❌ | 必须重启 |
| 拒绝策略 | ❌ | ❌ | 必须重启 |
| 线程池名称/标识符 | ❌ | ❌ | 必须重启 |
二、开发环境配置
JDK 8+:基础开发环境。
Maven 3.8.x:依赖管理和项目构建。
Redis 6.2.x:作为注册中心存储配置和消息通信。
Examples - Apache ECharts - 百度的图表工具,可以用于线程监控展示
三、代码实现
父pom.xml 依赖文件
父POM定义了多模块项目结构(管理后台、测试模块、Spring Boot Starter模块),统一管理依赖版本(如Guava、Fastjson、Redisson),并配置了Maven插件(如编译器、资源处理)。
XML
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<!-- 项目基本信息配置 -->
<modelVersion>4.0.0</modelVersion>
<groupId>com.yang</groupId>
<artifactId>Dynamic-thread-pool</artifactId>
<version>1.0</version>
<!-- packaging为pom表示这是一个多模块聚合项目 -->
<packaging>pom</packaging>
<!-- 定义子模块,Maven会按顺序构建这些模块 -->
<modules>
<module>Dynamic-thread-pool-admin</module> <!-- 管理后台模块 -->
<module>Dynamic-thread-pool-test</module> <!-- 测试模块 -->
<module>Dynamic-thread-pool-spring-boot-starter</module> <!-- Spring Boot starter模块 -->
</modules>
<!-- 项目属性配置 -->
<properties>
<maven.compiler.source>17</maven.compiler.source> <!-- Java源代码版本 -->
<maven.compiler.target>17</maven.compiler.target> <!-- 目标字节码版本 -->
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <!-- 文件编码 -->
</properties>
<!-- 继承Spring Boot父POM,简化Spring Boot项目配置 -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.12</version> <!-- 使用Spring Boot 2.7.12版本 -->
<relativePath/> <!-- 不从相对路径查找父POM -->
</parent>
<!-- 依赖管理:统一管理所有子模块的依赖版本 -->
<dependencyManagement>
<dependencies>
<!-- Google Guava工具库 -->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>32.1.3-jre</version> <!-- 线程池可能用到的高并发工具类 -->
</dependency>
<!-- Apache Commons Lang工具库 -->
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.6</version> <!-- 字符串、对象操作等工具 -->
</dependency>
<!-- 编解码工具库 -->
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.15</version> <!-- 可能用于配置加密等 -->
</dependency>
<!-- 阿里巴巴JSON处理库 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>2.0.49</version> <!-- 用于配置的JSON序列化/反序列化 -->
</dependency>
<!-- JUnit测试框架 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.1</version>
<scope>test</scope> <!-- 仅在测试范围有效 -->
</dependency>
</dependencies>
</dependencyManagement>
<!-- 构建配置 -->
<build>
<!-- 最终打包的文件名 -->
<finalName>dynamic-thread-pool</finalName>
<!-- 资源文件处理配置 -->
<resources>
<resource>
<directory>src/main/resources</directory> <!-- 主资源目录 -->
<filtering>true</filtering> <!-- 启用资源过滤(替换占位符) -->
</resource>
<resource>
<directory>src/assembly/resources</directory> <!-- 打包资源目录 -->
<filtering>false</filtering> <!-- 不启用过滤 -->
</resource>
</resources>
<!-- 测试资源文件配置 -->
<testResources>
<testResource>
<directory>src/test/resources</directory> <!-- 测试资源目录 -->
<filtering>true</filtering>
</testResource>
<testResource>
<directory>src/main/resources</directory> <!-- 测试时也使用主资源 -->
<filtering>true</filtering>
</testResource>
</testResources>
<!-- Maven插件配置 -->
<plugins>
<!-- Maven Archetype插件:用于创建项目模板 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-archetype-plugin</artifactId>
<version>3.2.0</version>
</plugin>
<!-- Java编译器插件 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.0</version>
<configuration>
<source>${java.version}</source> <!-- 使用properties中定义的Java版本 -->
<target>${java.version}</target>
<encoding>${project.build.sourceEncoding}</encoding> <!-- 使用UTF-8编码 -->
</configuration>
</plugin>
<!-- 资源处理插件 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>2.5</version>
<configuration>
<encoding>UTF-8</encoding> <!-- 资源文件编码 -->
</configuration>
</plugin>
<!-- 版本管理插件:用于检查依赖版本 -->
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>versions-maven-plugin</artifactId>
<version>2.7</version>
</plugin>
</plugins>
</build>
</project>
spring-boot-starter模块
pom.xml 依赖文件
引入Spring Boot核心依赖(如spring-boot-starter-aop)、Redisson(用于Redis通信)和工具库(如commons-lang)。
XML
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<!-- 继承父项目,复用父POM中的配置 -->
<parent>
<groupId>com.yang</groupId>
<artifactId>Dynamic-thread-pool</artifactId>
<version>1.0</version>
</parent>
<artifactId>Dynamic-thread-pool-spring-boot-starter</artifactId>
<!-- 注意:这里没有指定packaging,默认是jar -->
<!-- 依赖配置 -->
<dependencies>
<!-- Spring Boot核心starter:提供基础Spring功能 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<!-- 配置处理器:生成配置元数据,可选依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional> <!-- 编译时需要,运行时不需要 -->
</dependency>
<!-- Spring Boot自动配置:支持@EnableAutoConfiguration -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
</dependency>
<!-- 🔴 重要:AOP支持,用于拦截线程池操作 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<!-- Spring Boot测试支持 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- Apache Commons工具库:提供基础工具类 -->
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
</dependency>
<!-- 阿里巴巴JSON库:用于配置序列化 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
</dependency>
<!-- JUnit测试框架 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<!-- 🔴 核心:Redisson分布式框架,用于配置同步和监控 -->
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson-spring-boot-starter</artifactId>
<version>3.26.0</version>
</dependency>
</dependencies>
<build>
<!-- 最终打包的文件名 -->
<finalName>dynamic-thread-pool-spring-boot-starter</finalName>
<!-- 资源文件处理 -->
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering> <!-- 启用占位符替换 -->
<includes>
<include>**/**</include> <!-- 包含所有资源文件 -->
</includes>
</resource>
</resources>
<!-- 测试资源文件处理 -->
<testResources>
<testResource>
<directory>src/test/resources</directory>
<filtering>true</filtering>
<includes>
<include>**/**</include>
</includes>
</testResource>
</testResources>
<!-- Maven插件配置 -->
<plugins>
<!-- Maven Surefire插件:用于执行单元测试 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.12.4</version>
<configuration>
<skipTests>true</skipTests> <!-- 跳过测试执行 -->
</configuration>
</plugin>
<!-- 资源文件编码插件 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>2.5</version>
<configuration>
<encoding>${project.build.sourceEncoding}</encoding> <!-- UTF-8编码 -->
</configuration>
</plugin>
<!-- Java编译器插件 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>${maven.compiler.source}</source> <!-- Java 8 -->
<target>${maven.compiler.target}</target> <!-- Java 8 -->
<encoding>${project.build.sourceEncoding}</encoding> <!-- UTF-8 -->
</configuration>
</plugin>
<!-- 源码打包插件:生成源码JAR -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>2.1.2</version>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar</goal> <!-- 生成源码JAR包 -->
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
ThreadPoolConfigEntity 线程池配置实体对象
线程池配置实体类,封装核心线程数、队列大小等属性。
java
/**
* @author yang
* @description 线程池配置实体对象
*/
public class ThreadPoolConfigEntity {
/** 应用名称 */
private String appName;
/** 线程池名称 */
private String threadPoolName;
/** 核心线程数 */
private int corePoolSize;
/** 最大线程数 */
private int maximumPoolSize;
/** 当前活跃线程数 */
private int activeCount;
/** 当前池中线程数 */
private int poolSize;
/** 队列类型 */
private String queueType;
/** 当前队列任务数 */
private int queueSize;
/** 队列剩余任务数 */
private int remainingCapacity;
public ThreadPoolConfigEntity() {
}
public ThreadPoolConfigEntity(String appName, String threadPoolName) {
this.appName = appName;
this.threadPoolName = threadPoolName;
}
public String getAppName() {
return appName;
}
public String getThreadPoolName() {
return threadPoolName;
}
public int getCorePoolSize() {
return corePoolSize;
}
public void setCorePoolSize(int corePoolSize) {
this.corePoolSize = corePoolSize;
}
public int getMaximumPoolSize() {
return maximumPoolSize;
}
public void setMaximumPoolSize(int maximumPoolSize) {
this.maximumPoolSize = maximumPoolSize;
}
public int getActiveCount() {
return activeCount;
}
public void setActiveCount(int activeCount) {
this.activeCount = activeCount;
}
public int getPoolSize() {
return poolSize;
}
public void setPoolSize(int poolSize) {
this.poolSize = poolSize;
}
public String getQueueType() {
return queueType;
}
public void setQueueType(String queueType) {
this.queueType = queueType;
}
public int getQueueSize() {
return queueSize;
}
public void setQueueSize(int queueSize) {
this.queueSize = queueSize;
}
public int getRemainingCapacity() {
return remainingCapacity;
}
public void setRemainingCapacity(int remainingCapacity) {
this.remainingCapacity = remainingCapacity;
}
}
RegistryEnumVO 注册中心枚举值对象
定义Redis存储的键和描述(如配置列表、参数键)。
java
/**
* @author yang
* @description 注册中心枚举值对象 key
*/
public enum RegistryEnumVO {
THREAD_POOL_CONFIG_LIST_KEY("THREAD_POOL_CONFIG_LIST_KEY", "池化配置列表"),
THREAD_POOL_CONFIG_PARAMETER_LIST_KEY("THREAD_POOL_CONFIG_PARAMETER_LIST_KEY", "池化配置参数"),
DYNAMIC_THREAD_POOL_REDIS_TOPIC("DYNAMIC_THREAD_POOL_REDIS_TOPIC", "动态线程池监听主题配置");
private final String key;
private final String desc;
RegistryEnumVO(String key, String desc) {
this.key = key;
this.desc = desc;
}
public String getKey() {
return key;
}
public String getDesc() {
return desc;
}
}
IDynamicThreadPoolService 动态线程池服务接口
接口定义查询和更新线程池配置的方法。
java
/**
* @author yang
* @description 动态线程池服务
*/
public interface IDynamicThreadPoolService {
/** 查询线程池列表 */
List<ThreadPoolConfigEntity> queryThreadPoolList();
/** 查询线程池配置 */
ThreadPoolConfigEntity queryThreadPoolConfigByName(String threadPoolName);
/** 更新线程池配置 */
void updateThreadPoolConfig(ThreadPoolConfigEntity threadPoolConfigEntity);
}
DynamicThreadPoolService 动态线程池服务
实现类,通过ThreadPoolExecutor映射表管理线程池,支持动态调整核心参数(setCorePoolSize、setMaximumPoolSize)。
java
/**
* @author yang
* @description 动态线程池服务
*/
public class DynamicThreadPoolService implements IDynamicThreadPoolService {
// 日志记录器
private final Logger logger = LoggerFactory.getLogger(DynamicThreadPoolService.class);
// 应用名称,用于标识当前服务实例
private final String applicationName;
// 线程池映射表,key为线程池名称,value为对应的ThreadPoolExecutor实例
private final Map<String, ThreadPoolExecutor> threadPoolExecutorMap;
// 构造函数,注入应用名称和线程池映射表
public DynamicThreadPoolService(String applicationName, Map<String, ThreadPoolExecutor> threadPoolExecutorMap) {
this.applicationName = applicationName;
this.threadPoolExecutorMap = threadPoolExecutorMap;
}
/**
* 查询所有线程池的配置信息列表
* @return 返回包含所有线程池配置信息的列表
*/
@Override
public List<ThreadPoolConfigEntity> queryThreadPoolList() {
// 获取所有线程池的Bean名称集合
Set<String> threadPoolBeanNames = threadPoolExecutorMap.keySet();
// 创建结果列表,预分配足够容量
List<ThreadPoolConfigEntity> threadPoolVOS = new ArrayList<>(threadPoolBeanNames.size());
// 遍历所有线程池
for (String beanName : threadPoolBeanNames) {
// 根据Bean名称获取对应的线程池实例
ThreadPoolExecutor threadPoolExecutor = threadPoolExecutorMap.get(beanName);
// 创建线程池配置实体对象,包含应用名和线程池名
ThreadPoolConfigEntity threadPoolConfigVO = new ThreadPoolConfigEntity(applicationName, beanName);
// 设置线程池的各项监控指标
threadPoolConfigVO.setCorePoolSize(threadPoolExecutor.getCorePoolSize()); // 核心线程数
threadPoolConfigVO.setMaximumPoolSize(threadPoolExecutor.getMaximumPoolSize()); // 最大线程数
threadPoolConfigVO.setActiveCount(threadPoolExecutor.getActiveCount()); // 活动线程数
threadPoolConfigVO.setPoolSize(threadPoolExecutor.getPoolSize()); // 当前线程池大小
threadPoolConfigVO.setQueueType(threadPoolExecutor.getQueue().getClass().getSimpleName()); // 队列类型
threadPoolConfigVO.setQueueSize(threadPoolExecutor.getQueue().size()); // 队列当前大小
threadPoolConfigVO.setRemainingCapacity(threadPoolExecutor.getQueue().remainingCapacity()); // 队列剩余容量
// 将配置信息添加到结果列表
threadPoolVOS.add(threadPoolConfigVO);
}
return threadPoolVOS;
}
/**
* 根据线程池名称查询特定线程池的配置信息
* @param threadPoolName 线程池名称
* @return 返回指定线程池的配置信息实体
*/
@Override
public ThreadPoolConfigEntity queryThreadPoolConfigByName(String threadPoolName) {
// 根据线程池名称获取对应的线程池实例
ThreadPoolExecutor threadPoolExecutor = threadPoolExecutorMap.get(threadPoolName);
// 如果线程池不存在,返回一个只包含应用名和线程池名的空实体
if (null == threadPoolExecutor) return new ThreadPoolConfigEntity(applicationName, threadPoolName);
// 创建线程池配置实体对象
ThreadPoolConfigEntity threadPoolConfigVO = new ThreadPoolConfigEntity(applicationName, threadPoolName);
// 设置线程池的各项监控指标
threadPoolConfigVO.setCorePoolSize(threadPoolExecutor.getCorePoolSize()); // 核心线程数
threadPoolConfigVO.setMaximumPoolSize(threadPoolExecutor.getMaximumPoolSize()); // 最大线程数
threadPoolConfigVO.setActiveCount(threadPoolExecutor.getActiveCount()); // 活动线程数
threadPoolConfigVO.setPoolSize(threadPoolExecutor.getPoolSize()); // 当前线程池大小
threadPoolConfigVO.setQueueType(threadPoolExecutor.getQueue().getClass().getSimpleName()); // 队列类型
threadPoolConfigVO.setQueueSize(threadPoolExecutor.getQueue().size()); // 队列当前大小
threadPoolConfigVO.setRemainingCapacity(threadPoolExecutor.getQueue().remainingCapacity()); // 队列剩余容量
// 如果开启debug日志,记录查询详情
if (logger.isDebugEnabled()) {
logger.info("动态线程池,配置查询 应用名:{} 线程名:{} 池化配置:{}", applicationName, threadPoolName, JSON.toJSONString(threadPoolConfigVO));
}
return threadPoolConfigVO;
}
/**
* 更新线程池配置参数
* @param threadPoolConfigEntity 包含新配置参数的实体对象
*/
@Override
public void updateThreadPoolConfig(ThreadPoolConfigEntity threadPoolConfigEntity) {
// 参数校验:配置实体不能为空,且应用名必须匹配当前服务实例
if (null == threadPoolConfigEntity) {
logger.warn("动态线程池,配置更新失败,配置实体为空");
return;
}
if (!applicationName.equals(threadPoolConfigEntity.getAppName())) {
logger.warn("动态线程池,配置更新失败,应用名:{} 线程名:{} 参数错误", applicationName, threadPoolConfigEntity.getThreadPoolName());
return;
}
// 根据线程池名称获取对应的线程池实例
ThreadPoolExecutor threadPoolExecutor = threadPoolExecutorMap.get(threadPoolConfigEntity.getThreadPoolName());
// 如果线程池不存在,直接返回
if (null == threadPoolExecutor) {
logger.warn("动态线程池,配置更新失败,该线程池不存在");
return;
}
// 动态调整线程池参数
// 设置核心线程数(允许实时调整)
threadPoolExecutor.setCorePoolSize(threadPoolConfigEntity.getCorePoolSize());
// 设置最大线程数(允许实时调整)
threadPoolExecutor.setMaximumPoolSize(threadPoolConfigEntity.getMaximumPoolSize());
// 注意:这里只调整了核心线程数和最大线程数,队列大小等参数需要重启线程池才能生效
}
}
DynamicThreadPoolAutoProperties 动态线程池配置
java
/**
* @author yang
* @description 动态线程池配置
*/
@ConfigurationProperties(prefix = "dynamic.thread.pool.config", ignoreInvalidFields = true)
public class DynamicThreadPoolAutoProperties {
/** 状态;open = 开启、close 关闭 */
private boolean enable;
/** redis host */
private String host;
/** redis port */
private int port;
/** 账密 */
private String password;
/** 设置连接池的大小,默认为64 */
private int poolSize = 64;
/** 设置连接池的最小空闲连接数,默认为10 */
private int minIdleSize = 10;
/** 设置连接的最大空闲时间(单位:毫秒),超过该时间的空闲连接将被关闭,默认为10000 */
private int idleTimeout = 10000;
/** 设置连接超时时间(单位:毫秒),默认为10000 */
private int connectTimeout = 10000;
/** 设置连接重试次数,默认为3 */
private int retryAttempts = 3;
/** 设置连接重试的间隔时间(单位:毫秒),默认为1000 */
private int retryInterval = 1000;
/** 设置定期检查连接是否可用的时间间隔(单位:毫秒),默认为0,表示不进行定期检查 */
private int pingInterval = 0;
/** 设置是否保持长连接,默认为true */
private boolean keepAlive = true;
public boolean isEnable() {
return enable;
}
public void setEnable(boolean enable) {
this.enable = enable;
}
public String getHost() {
return host;
}
public void setHost(String host) {
this.host = host;
}
public int getPort() {
return port;
}
public void setPort(int port) {
this.port = port;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public int getPoolSize() {
return poolSize;
}
public void setPoolSize(int poolSize) {
this.poolSize = poolSize;
}
public int getMinIdleSize() {
return minIdleSize;
}
public void setMinIdleSize(int minIdleSize) {
this.minIdleSize = minIdleSize;
}
public int getIdleTimeout() {
return idleTimeout;
}
public void setIdleTimeout(int idleTimeout) {
this.idleTimeout = idleTimeout;
}
public int getConnectTimeout() {
return connectTimeout;
}
public void setConnectTimeout(int connectTimeout) {
this.connectTimeout = connectTimeout;
}
public int getRetryAttempts() {
return retryAttempts;
}
public void setRetryAttempts(int retryAttempts) {
this.retryAttempts = retryAttempts;
}
public int getRetryInterval() {
return retryInterval;
}
public void setRetryInterval(int retryInterval) {
this.retryInterval = retryInterval;
}
public int getPingInterval() {
return pingInterval;
}
public void setPingInterval(int pingInterval) {
this.pingInterval = pingInterval;
}
public boolean isKeepAlive() {
return keepAlive;
}
public void setKeepAlive(boolean keepAlive) {
this.keepAlive = keepAlive;
}
}
DynamicThreadPoolAutoConfig 动态配置入口
Spring Boot自动配置类,初始化Redisson客户端、注册中心和服务Bean,并绑定定时任务(数据上报)和消息监听(参数调整)。
java
/**
* @author yang
* @description 动态配置入口
* 功能:动态线程池SDK的自动配置类,负责初始化所有相关组件
*/
@Configuration
@EnableConfigurationProperties(DynamicThreadPoolAutoProperties.class) // 启用配置属性绑定
@EnableScheduling // 启用Spring定时任务功能
public class DynamicThreadPoolAutoConfig {
private final Logger logger = LoggerFactory.getLogger(DynamicThreadPoolAutoConfig.class);
private String applicationName; // 应用名称,用于标识当前服务实例
/**
* 创建Redisson客户端Bean
* Bean名称:dynamicThreadRedissonClient
* 用途:提供Redis连接,用于线程池配置的存储和消息通信
*/
@Bean("dynamicThreadRedissonClient")
public RedissonClient redissonClient(DynamicThreadPoolAutoProperties properties) {
Config config = new Config();
// 设置JSON序列化编解码器,支持复杂对象存储
config.setCodec(JsonJacksonCodec.INSTANCE);
// 单机模式Redis配置
config.useSingleServer()
.setAddress("redis://" + properties.getHost() + ":" + properties.getPort()) // Redis地址
.setPassword(properties.getPassword()) // Redis密码
.setConnectionPoolSize(properties.getPoolSize()) // 连接池大小
.setConnectionMinimumIdleSize(properties.getMinIdleSize()) // 最小空闲连接数
.setIdleConnectionTimeout(properties.getIdleTimeout()) // 空闲连接超时时间
.setConnectTimeout(properties.getConnectTimeout()) // 连接超时时间
.setRetryAttempts(properties.getRetryAttempts()) // 重试次数
.setRetryInterval(properties.getRetryInterval()) // 重试间隔
.setPingConnectionInterval(properties.getPingInterval()) // 心跳检测间隔
.setKeepAlive(properties.isKeepAlive()) // 是否保持长连接
;
RedissonClient redissonClient = Redisson.create(config);
logger.info("动态线程池,注册器(redis)初始化完成。{} {} {}",
properties.getHost(), properties.getPoolSize(), !redissonClient.isShutdown());
return redissonClient;
}
/**
* 创建Redis注册中心Bean
* 用途:提供线程池配置的存储和查询能力
*/
@Bean
public IRegistry redisRegistry(RedissonClient dynamicThreadRedissonClient) {
return new RedisRegistry(dynamicThreadRedissonClient);
}
/**
* 创建动态线程池服务Bean
* Bean名称:dynamicThreadPollService
* 功能:核心服务类,提供线程池管理和配置操作
*/
@Bean("dynamicThreadPollService")
public DynamicThreadPoolService dynamicThreadPollService(ApplicationContext applicationContext,
Map<String, ThreadPoolExecutor> threadPoolExecutorMap,
RedissonClient redissonClient) {
// 从Spring环境变量获取应用名称
applicationName = applicationContext.getEnvironment().getProperty("spring.application.name");
if (StringUtils.isBlank(applicationName)) {
applicationName = "";
logger.warn("SpringBoot 应用未配置 spring.application.name !");
}
// 应用启动时:从Redis加载线程池配置并应用到本地线程池
Set<String> threadPoolKeys = threadPoolExecutorMap.keySet();
for (String threadPoolKey : threadPoolKeys) {
// 构建Redis Key:格式为"配置参数Key_应用名_线程池名"
String redisKey = RegistryEnumVO.THREAD_POOL_CONFIG_PARAMETER_LIST_KEY.getKey() + "_" + applicationName + "_" + threadPoolKey;
ThreadPoolConfigEntity threadPoolConfigEntity = redissonClient.<ThreadPoolConfigEntity>getBucket(redisKey).get();
// 如果Redis中不存在配置,则应用本地线程池
if (null == threadPoolConfigEntity) {
continue;
}
ThreadPoolExecutor threadPoolExecutor = threadPoolExecutorMap.get(threadPoolKey);
// 动态调整线程池参数
threadPoolExecutor.setCorePoolSize(threadPoolConfigEntity.getCorePoolSize());
threadPoolExecutor.setMaximumPoolSize(threadPoolConfigEntity.getMaximumPoolSize());
}
// 创建动态线程池服务实例
return new DynamicThreadPoolService(applicationName, threadPoolExecutorMap);
}
/**
* 创建线程池数据上报任务Bean
* 功能:定时上报线程池运行状态到注册中心
*/
@Bean
public ThreadPoolDataReportJob threadPoolDataReportJob(IDynamicThreadPoolService dynamicThreadPoolService, IRegistry registry) {
return new ThreadPoolDataReportJob(dynamicThreadPoolService, registry);
}
/**
* 创建线程池配置调整监听器Bean
* 功能:监听配置变更消息并实时调整线程池参数
*/
@Bean
public ThreadPoolConfigAdjustListener threadPoolConfigAdjustListener(IDynamicThreadPoolService dynamicThreadPoolService, IRegistry registry) {
return new ThreadPoolConfigAdjustListener(dynamicThreadPoolService, registry);
}
/**
* 创建Redis消息主题Bean
* Bean名称:dynamicThreadPoolRedisTopic
* 功能:建立配置变更的消息通道,实现动态调整
*/
@Bean(name = "dynamicThreadPoolRedisTopic")
public RTopic threadPoolConfigAdjustListener(RedissonClient redissonClient,
ThreadPoolConfigAdjustListener threadPoolConfigAdjustListener) {
// 构建应用专属的消息主题
String topicKey = RegistryEnumVO.DYNAMIC_THREAD_POOL_REDIS_TOPIC.getKey() + "_" + applicationName;
RTopic topic = redissonClient.getTopic(topicKey);
// 注册消息监听器,监听ThreadPoolConfigEntity类型的消息
topic.addListener(ThreadPoolConfigEntity.class, threadPoolConfigAdjustListener);
return topic;
}
}
IRegistry 注册中心接口
接口定义数据上报方法。
java
/**
* @author yang
* @description 注册中心接口
*/
public interface IRegistry {
/** 上报所有线程池配置列表 */
void reportThreadPool(List<ThreadPoolConfigEntity> threadPoolEntities);
/** 上报指定线程池的配置信息 */
void reportThreadPoolConfigParameter(ThreadPoolConfigEntity threadPoolConfigEntity);
}
RedisRegistry 注册中心服务
通过Redisson操作Redis,存储线程池配置(如RList存储列表,RBucket存储单条配置)。
java
/**
* @author yang
* @description Redis 注册中心
*/
public class RedisRegistry implements IRegistry {
// Redisson客户端,用于操作Redis
private final RedissonClient redissonClient;
// 构造函数,注入Redisson客户端
public RedisRegistry(RedissonClient redissonClient) {
this.redissonClient = redissonClient;
}
/**
* 上报线程池配置列表到Redis
* 用于存储所有线程池的完整配置信息
* @param threadPoolEntities 线程池配置实体列表
*/
@Override
public void reportThreadPool(List<ThreadPoolConfigEntity> threadPoolEntities) {
// 获取Redis中的List数据结构,用于存储线程池配置列表
RList<ThreadPoolConfigEntity> list = redissonClient.getList(RegistryEnumVO.THREAD_POOL_CONFIG_LIST_KEY.getKey());
// 先清空现有数据,然后添加新的配置列表
list.delete(); // 删除原有的所有配置
list.addAll(threadPoolEntities); // 批量添加新的线程池配置
}
/**
* 上报单个线程池的详细配置参数到Redis
* 用于存储特定线程池的实时运行参数和状态
* @param threadPoolConfigEntity 线程池配置实体
*/
@Override
public void reportThreadPoolConfigParameter(ThreadPoolConfigEntity threadPoolConfigEntity) {
// 构建缓存Key:格式为"配置参数Key_应用名_线程池名",确保唯一性
String cacheKey = RegistryEnumVO.THREAD_POOL_CONFIG_PARAMETER_LIST_KEY.getKey() + "_" +
threadPoolConfigEntity.getAppName() + "_" +
threadPoolConfigEntity.getThreadPoolName();
// 获取Redis中的Bucket(键值对)数据结构
RBucket<ThreadPoolConfigEntity> bucket = redissonClient.getBucket(cacheKey);
// 存储线程池配置,设置30天的过期时间
bucket.set(threadPoolConfigEntity, Duration.ofDays(30));
}
}
ThreadPoolDataReportJob 线程池数据上报任务
定时任务,采集线程池状态并上报Redis。
java
/**
* @author yang
* @description 线程池数据上报任务
* 功能:定时采集线程池运行数据并上报到注册中心
*/
public class ThreadPoolDataReportJob {
// 日志记录器
private final Logger logger = LoggerFactory.getLogger(ThreadPoolDataReportJob.class);
// 动态线程池服务,用于查询线程池状态
private final IDynamicThreadPoolService dynamicThreadPoolService;
// 注册中心,用于数据上报
private final IRegistry registry;
// 构造函数,注入依赖服务
public ThreadPoolDataReportJob(IDynamicThreadPoolService dynamicThreadPoolService, IRegistry registry) {
this.dynamicThreadPoolService = dynamicThreadPoolService;
this.registry = registry;
}
/**
* 定时执行线程池数据上报任务
* 执行频率:每20秒执行一次(cron表达式:0/20 * * * * ?)
* 功能:采集所有线程池的实时运行数据并上报到注册中心
*/
@Scheduled(cron = "0/20 * * * * ?")
public void execReportThreadPoolList() {
// 查询所有线程池的当前配置和运行状态
List<ThreadPoolConfigEntity> threadPoolConfigEntities = dynamicThreadPoolService.queryThreadPoolList();
// 上报线程池配置列表(批量上报)
registry.reportThreadPool(threadPoolConfigEntities);
logger.info("动态线程池,上报线程池信息:{}", JSON.toJSONString(threadPoolConfigEntities));
// 遍历每个线程池,单独上报详细配置参数
for (ThreadPoolConfigEntity threadPoolConfigEntity : threadPoolConfigEntities) {
// 上报单个线程池的详细参数
registry.reportThreadPoolConfigParameter(threadPoolConfigEntity);
logger.info("动态线程池,上报线程池配置:{}", JSON.toJSONString(threadPoolConfigEntity));
}
}
}
ThreadPoolConfigAdjustListener 动态线程池变更监听
监听Redis消息,实时调整线程池参数。
java
/**
* @author yang
* @description 动态线程池变更监听
* 功能:监听线程池配置变更消息,并实时调整线程池参数
*/
public class ThreadPoolConfigAdjustListener implements MessageListener<ThreadPoolConfigEntity> {
// 日志记录器
private Logger logger = LoggerFactory.getLogger(ThreadPoolConfigAdjustListener.class);
// 动态线程池服务,用于操作线程池配置
private final IDynamicThreadPoolService dynamicThreadPoolService;
// 注册中心,用于上报线程池状态
private final IRegistry registry;
// 构造函数,注入依赖服务
public ThreadPoolConfigAdjustListener(IDynamicThreadPoolService dynamicThreadPoolService, IRegistry registry) {
this.dynamicThreadPoolService = dynamicThreadPoolService;
this.registry = registry;
}
/**
* 消息监听回调方法
* 当接收到线程池配置变更消息时触发执行
* @param charSequence 消息通道名称(Redis Topic)
* @param threadPoolConfigEntity 接收到的线程池配置实体
*/
@Override
public void onMessage(CharSequence charSequence, ThreadPoolConfigEntity threadPoolConfigEntity) {
// 记录配置变更日志
logger.info("动态线程池,调整线程池配置。线程池名称:{} 核心线程数:{} 最大线程数:{}",
threadPoolConfigEntity.getThreadPoolName(),
threadPoolConfigEntity.getCorePoolSize(),
threadPoolConfigEntity.getMaximumPoolSize());
// 执行线程池配置更新(核心操作)
dynamicThreadPoolService.updateThreadPoolConfig(threadPoolConfigEntity);
// 更新后上报最新数据到注册中心
// 上报所有线程池的完整配置列表
List<ThreadPoolConfigEntity> threadPoolConfigEntities = dynamicThreadPoolService.queryThreadPoolList();
registry.reportThreadPool(threadPoolConfigEntities);
// 上报特定线程池的详细配置参数
ThreadPoolConfigEntity threadPoolConfigEntityCurrent = dynamicThreadPoolService.queryThreadPoolConfigByName(threadPoolConfigEntity.getThreadPoolName());
registry.reportThreadPoolConfigParameter(threadPoolConfigEntityCurrent);
// 记录上报完成日志
logger.info("动态线程池,上报线程池配置:{}", JSON.toJSONString(threadPoolConfigEntity));
}
}
spring.factories 配置文件
SPI(Service Provider Interface)是一种服务发现机制,允许框架在运行时动态加载实现类。
在Java中,SPI通常通过在META-INF/services或META-INF/spring.factories等配置文件中声明接口的实现类来实现。
Spring Boot利用SPI机制实现自动装配(AutoConfiguration)。开发人员只需在组件的META-INF/spring.factories文件中配置自动配置类,Spring Boot启动时便会自动加载并初始化这些类。
java
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.yang.dynamic.thread.pool.sdk.config.DynamicThreadPoolAutoConfig
Admin管理端模块
pom.xml
它继承了父项目的配置,并添加了特定的依赖项,如Spring Boot Web支持、Redisson分布式锁和缓存支持、Lombok等。构建配置包括资源文件处理、测试资源文件处理以及Maven插件的配置,如Maven Surefire插件和Spring Boot Maven插件,用于打包可执行的JAR文件。
XML
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<!-- 继承父项目,复用父POM中的配置 -->
<parent>
<groupId>com.yang</groupId>
<artifactId>Dynamic-thread-pool</artifactId>
<version>1.0</version>
</parent>
<artifactId>Dynamic-thread-pool-admin</artifactId>
<packaging>jar</packaging> <!-- 打包为可执行JAR -->
<!-- 依赖配置 -->
<dependencies>
<!-- Spring Boot Web支持:提供管理后台的REST API -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Spring Boot测试支持 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- 配置处理器:用于处理@ConfigurationProperties注解 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
</dependency>
<!-- 阿里巴巴JSON库:用于API数据序列化 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
</dependency>
<!-- Apache Commons工具库:提供工具类支持 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<!-- Lombok:简化代码编写 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!-- JUnit测试框架 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<!-- 编解码工具:可能用于安全认证或数据编码 -->
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
</dependency>
<!-- 🔴 重要区别:Redisson分布式锁和缓存支持 -->
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson-spring-boot-starter</artifactId>
<version>3.26.0</version> <!-- 用于分布式环境下的线程池管理 -->
</dependency>
</dependencies>
<build>
<!-- 最终打包的文件名 -->
<finalName>dynamic-thread-pool-admin-app</finalName>
<!-- 资源文件处理 -->
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering> <!-- 启用配置文件占位符替换 -->
<includes>
<include>**/**</include> <!-- 包含所有资源文件 -->
</includes>
</resource>
</resources>
<!-- 测试资源文件处理 -->
<testResources>
<testResource>
<directory>src/test/resources</directory>
<filtering>true</filtering>
<includes>
<include>**/**</include>
</includes>
</testResource>
</testResources>
<!-- Maven插件配置 -->
<plugins>
<!-- Maven Surefire插件:用于执行单元测试 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.6</version>
<configuration>
<skipTests>true</skipTests> <!-- 跳过测试执行 -->
<testFailureIgnore>false</testFailureIgnore> <!-- 测试失败不忽略 -->
<includes>
<include>**/*Test.java</include> <!-- 匹配测试类 -->
</includes>
</configuration>
</plugin>
<!-- Spring Boot Maven插件:打包可执行JAR -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<!-- 管理后台启动类 -->
<mainClass>com.yang.dynamic.thread.pool.Application</mainClass>
<layout>JAR</layout>
</configuration>
</plugin>
</plugins>
</build>
</project>
application.yml 配置文件
设置了管理端的基本配置,包括服务器端口、Redis连接参数(如主机、端口、连接池大小、空闲连接数等)和日志级别。这些配置确保了管理端能够正确连接到Redis并运行在指定的端口上。
javascript
server:
port: 8089
redis:
sdk:
config:
host: localhost
port: 6379
pool-size: 10
min-idle-size: 5
idle-timeout: 30000
connect-timeout: 5000
retry-attempts: 3
retry-interval: 1000
ping-interval: 60000
keep-alive: true
logging:
level:
root: info
config: classpath:logback-spring.xml
Response 返回类实体
用于封装API的响应数据。它包含状态码(code)、信息(info)和实际数据(data)。通过使用Lombok注解简化了代码,提供了构建器模式来创建响应对象。状态码枚举定义了常见的响应状态,如成功、失败和非法参数。
java
package com.yang.dynamic.thread.pool.types;
import lombok.*;
import java.io.Serializable;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Response<T> implements Serializable {
private static final long serialVersionUID = -2474596551402989285L;
private String code;
private String info;
private T data;
@AllArgsConstructor
@NoArgsConstructor
@Getter
public enum Code {
SUCCESS("0000", "调用成功"),
UN_ERROR("0001", "调用失败"),
ILLEGAL_PARAMETER("0002", "非法参数"),
;
private String code;
private String info;
}
}
ThreadPoolConfigEntity 线程池配置信息实体类
用于封装线程池的配置信息,包括应用名称、线程池名称、核心线程数、最大线程数、活跃线程数等。这个实体类在管理端和客户端之间传递线程池的配置信息,确保数据的一致性和完整性。
java
package com.yang.dynamic.thread.pool.sdk.domain.model.entity;
public class ThreadPoolConfigEntity {
/** 应用名称 */
private String appName;
/** 线程池名称 */
private String threadPoolName;
/** 核心线程数 */
private int corePoolSize;
/** 最大线程数 */
private int maximumPoolSize;
/** 当前活跃线程数 */
private int activeCount;
/** 当前池中线程数 */
private int poolSize;
/** 队列类型 */
private String queueType;
/** 当前队列任务数 */
private int queueSize;
/** 队列剩余任务数 */
private int remainingCapacity;
public ThreadPoolConfigEntity() {
}
public ThreadPoolConfigEntity(String appName, String threadPoolName) {
this.appName = appName;
this.threadPoolName = threadPoolName;
}
public String getAppName() {
return appName;
}
public String getThreadPoolName() {
return threadPoolName;
}
public int getCorePoolSize() {
return corePoolSize;
}
public void setCorePoolSize(int corePoolSize) {
this.corePoolSize = corePoolSize;
}
public int getMaximumPoolSize() {
return maximumPoolSize;
}
public void setMaximumPoolSize(int maximumPoolSize) {
this.maximumPoolSize = maximumPoolSize;
}
public int getActiveCount() {
return activeCount;
}
public void setActiveCount(int activeCount) {
this.activeCount = activeCount;
}
public int getPoolSize() {
return poolSize;
}
public void setPoolSize(int poolSize) {
this.poolSize = poolSize;
}
public String getQueueType() {
return queueType;
}
public void setQueueType(String queueType) {
this.queueType = queueType;
}
public int getQueueSize() {
return queueSize;
}
public void setQueueSize(int queueSize) {
this.queueSize = queueSize;
}
public int getRemainingCapacity() {
return remainingCapacity;
}
public void setRemainingCapacity(int remainingCapacity) {
this.remainingCapacity = remainingCapacity;
}
}
DynamicThreadPoolController 操作线程池配置接口
提供了三个主要接口:
查询线程池列表:从Redis获取所有线程池的配置列表。
查询线程池配置:根据应用名和线程池名查询特定的线程池配置。
修改线程池配置:通过Redis的发布订阅模式动态修改线程池配置。这些接口通过Redisson客户端与Redis交互,实现了线程池配置的动态管理。
java
package com.yang.dynamic.thread.pool.trigger;
import com.alibaba.fastjson.JSON;
import com.yang.dynamic.thread.pool.sdk.domain.model.entity.ThreadPoolConfigEntity;
import com.yang.dynamic.thread.pool.types.Response;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RList;
import org.redisson.api.RTopic;
import org.redisson.api.RedissonClient;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.List;
@Slf4j
@RestController()
@CrossOrigin("*") // 允许所有跨域请求
@RequestMapping("/api/v1/dynamic/thread/pool/")
public class DynamicThreadPoolController {
@Resource
public RedissonClient redissonClient; // Redis 客户端,用于数据操作
/**
* 查询线程池数据
* 接口:GET /api/v1/dynamic/thread/pool/query_thread_pool_list
* 功能:获取所有线程池的配置列表
*
* 使用示例:
* curl --request GET \
* --url 'http://localhost:8089/api/v1/dynamic/thread/pool/query_thread_pool_list'
*/
@RequestMapping(value = "query_thread_pool_list", method = RequestMethod.GET)
public Response<List<ThreadPoolConfigEntity>> queryThreadPoolList() {
try {
// 从Redis获取线程池配置列表
RList<ThreadPoolConfigEntity> cacheList = redissonClient.getList("THREAD_POOL_CONFIG_LIST_KEY");
return Response.<List<ThreadPoolConfigEntity>>builder()
.code(Response.Code.SUCCESS.getCode())
.info(Response.Code.SUCCESS.getInfo())
.data(cacheList.readAll()) // 返回所有配置数据
.build();
} catch (Exception e) {
log.error("查询线程池数据异常", e);
return Response.<List<ThreadPoolConfigEntity>>builder()
.code(Response.Code.UN_ERROR.getCode())
.info(Response.Code.UN_ERROR.getInfo())
.build();
}
}
/**
* 查询线程池配置
* 接口:GET /api/v1/dynamic/thread/pool/query_thread_pool_config
* 功能:根据应用名和线程池名查询特定线程池配置
*
* 使用示例:
* curl --request GET \
* --url 'http://localhost:8089/api/v1/dynamic/thread/pool/query_thread_pool_config?appName=dynamic-thread-pool-test-app&threadPoolName=threadPoolExecutor'
*/
@RequestMapping(value = "query_thread_pool_config", method = RequestMethod.GET)
public Response<ThreadPoolConfigEntity> queryThreadPoolConfig(@RequestParam String appName, @RequestParam String threadPoolName) {
try {
// 构建缓存Key:格式为"KEY_应用名_线程池名"
String cacheKey = "THREAD_POOL_CONFIG_PARAMETER_LIST_KEY" + "_" + appName + "_" + threadPoolName;
// 从Redis获取特定线程池配置
ThreadPoolConfigEntity threadPoolConfigEntity = redissonClient.<ThreadPoolConfigEntity>getBucket(cacheKey).get();
return Response.<ThreadPoolConfigEntity>builder()
.code(Response.Code.SUCCESS.getCode())
.info(Response.Code.SUCCESS.getInfo())
.data(threadPoolConfigEntity)
.build();
} catch (Exception e) {
log.error("查询线程池配置异常", e);
return Response.<ThreadPoolConfigEntity>builder()
.code(Response.Code.UN_ERROR.getCode())
.info(Response.Code.UN_ERROR.getInfo())
.build();
}
}
/**
* 修改线程池配置
* 接口:POST /api/v1/dynamic/thread/pool/update_thread_pool_config
* 功能:通过消息机制动态修改线程池配置
*
* 使用示例:
* curl --request POST \
* --url http://localhost:8089/api/v1/dynamic/thread/pool/update_thread_pool_config \
* --header 'content-type: application/json' \
* --data '{
* "appName":"dynamic-thread-pool-test-app",
* "threadPoolName": "threadPoolExecutor",
* "corePoolSize": 1,
* "maximumPoolSize": 10
* }'
*/
@RequestMapping(value = "update_thread_pool_config", method = RequestMethod.POST)
public Response<Boolean> updateThreadPoolConfig(@RequestBody ThreadPoolConfigEntity threadPoolConfigEntity) {
try {
log.info("修改线程池配置开始 {} {} {}", threadPoolConfigEntity.getAppName(), threadPoolConfigEntity.getThreadPoolName(), JSON.toJSONString(threadPoolConfigEntity));
// 获取对应应用的消息主题
RTopic topic = redissonClient.getTopic("DYNAMIC_THREAD_POOL_REDIS_TOPIC" + "_" + threadPoolConfigEntity.getAppName());
// 发布配置变更消息(消息驱动架构)
topic.publish(threadPoolConfigEntity);
log.info("修改线程池配置完成 {} {}", threadPoolConfigEntity.getAppName(), threadPoolConfigEntity.getThreadPoolName());
return Response.<Boolean>builder()
.code(Response.Code.SUCCESS.getCode())
.info(Response.Code.SUCCESS.getInfo())
.data(true)
.build();
} catch (Exception e) {
log.error("修改线程池配置异常 {}", JSON.toJSONString(threadPoolConfigEntity), e);
return Response.<Boolean>builder()
.code(Response.Code.UN_ERROR.getCode())
.info(Response.Code.UN_ERROR.getInfo())
.data(false)
.build();
}
}
}
Application 主启动类
包含一个内部配置类RedisClientConfig,用于初始化Redisson客户端。RedisClientConfigProperties类通过@ConfigurationProperties注解绑定了Redis的配置参数,确保Redisson客户端能够正确连接到Redis服务器。
java
@SpringBootApplication
@Configurable
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class);
}
@Configuration
@EnableConfigurationProperties(RedisClientConfigProperties.class)
public static class RedisClientConfig {
@Bean("redissonClient")
public RedissonClient redissonClient(ConfigurableApplicationContext applicationContext, RedisClientConfigProperties properties) {
Config config = new Config();
// 根据需要可以设定编解码器;https://github.com/redisson/redisson/wiki/4.-%E6%95%B0%E6%8D%AE%E5%BA%8F%E5%88%97%E5%8C%96
config.setCodec(JsonJacksonCodec.INSTANCE);
// 单机模式
config.useSingleServer()
.setAddress("redis://" + properties.getHost() + ":" + properties.getPort())
.setConnectionPoolSize(properties.getPoolSize())
.setConnectionMinimumIdleSize(properties.getMinIdleSize())
.setIdleConnectionTimeout(properties.getIdleTimeout())
.setConnectTimeout(properties.getConnectTimeout())
.setRetryAttempts(properties.getRetryAttempts())
.setRetryInterval(properties.getRetryInterval())
.setPingConnectionInterval(properties.getPingInterval())
.setKeepAlive(properties.isKeepAlive())
;
return Redisson.create(config);
}
}
@Data
@ConfigurationProperties(prefix = "redis.sdk.config", ignoreInvalidFields = true)
public static class RedisClientConfigProperties {
/** host:ip */
private String host;
/** 端口 */
private int port;
/** 账密 */
private String password;
/** 设置连接池的大小,默认为64 */
private int poolSize = 64;
/** 设置连接池的最小空闲连接数,默认为10 */
private int minIdleSize = 10;
/** 设置连接的最大空闲时间(单位:毫秒),超过该时间的空闲连接将被关闭,默认为10000 */
private int idleTimeout = 10000;
/** 设置连接超时时间(单位:毫秒),默认为10000 */
private int connectTimeout = 10000;
/** 设置连接重试次数,默认为3 */
private int retryAttempts = 3;
/** 设置连接重试的间隔时间(单位:毫秒),默认为1000 */
private int retryInterval = 1000;
/** 设置定期检查连接是否可用的时间间隔(单位:毫秒),默认为0,表示不进行定期检查 */
private int pingInterval = 0;
/** 设置是否保持长连接,默认为true */
private boolean keepAlive = true;
}
}
Test模块
pom.xml 依赖文件
pom.xml文件继承了父项目的配置,并可能包含测试专用的依赖项。由于内容不完整,可以推测该模块用于单元测试和集成测试,确保动态线程池组件的各个功能模块能够正常工作。
XML
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<!-- 继承父项目,复用父POM中的配置 -->
<parent>
<groupId>com.yang</groupId>
<artifactId>Dynamic-thread-pool</artifactId>
<version>1.0</version>
</parent>
<!-- 打包为JAR,这是一个可执行的测试应用 -->
<packaging>jar</packaging>
<artifactId>Dynamic-thread-pool-test</artifactId>
<!-- 依赖配置 -->
<dependencies>
<!-- Spring Boot Web支持:提供REST API测试能力 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Spring Boot测试支持 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope> <!-- 仅在测试时使用 -->
</dependency>
<!-- 配置处理器:用于处理@ConfigurationProperties注解 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
</dependency>
<!-- 阿里巴巴JSON库:用于测试数据序列化 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
</dependency>
<!-- Apache Commons工具库:提供字符串、对象操作工具 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<!-- Lombok:简化Java Bean编写 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!-- JUnit测试框架 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<!-- 编解码工具:可能用于加密或编码测试 -->
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
</dependency>
<!-- 核心依赖:引入动态线程池starter进行集成测试 -->
<dependency>
<groupId>com.yang</groupId>
<artifactId>Dynamic-thread-pool-spring-boot-starter</artifactId>
<version>1.0</version>
</dependency>
</dependencies>
<!-- 构建配置 -->
<build>
<!-- 最终打包的文件名 -->
<finalName>dynamic-thread-pool-test-app</finalName>
<!-- 资源文件处理 -->
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering> <!-- 启用占位符替换 -->
<includes>
<include>**/**</include> <!-- 包含所有资源文件 -->
</includes>
</resource>
</resources>
<!-- 测试资源文件处理 -->
<testResources>
<testResource>
<directory>src/test/resources</directory>
<filtering>true</filtering>
<includes>
<include>**/**</include> <!-- 包含所有测试资源 -->
</includes>
</testResource>
</testResources>
<!-- Maven插件配置 -->
<plugins>
<!-- Maven Surefire插件:用于执行单元测试 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.6</version>
<configuration>
<skipTests>true</skipTests> <!-- 跳过测试执行(可能用于快速打包) -->
<testFailureIgnore>false</testFailureIgnore> <!-- 测试失败不忽略 -->
<includes>
<include>**/*Test.java</include> <!-- 只执行以Test结尾的测试类 -->
</includes>
</configuration>
</plugin>
<!-- Spring Boot Maven插件:用于打包可执行JAR -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<mainClass>com.yang.Application</mainClass> <!-- 应用启动类 -->
<layout>JAR</layout> <!-- 打包为可执行JAR -->
</configuration>
</plugin>
</plugins>
</build>
</project>
application.yml 配置文件
定义了应用的基本配置,包括服务器端口、线程池参数和动态线程池管理设置。
javascript
server:
port: 8093
# 线程池配置
thread:
pool:
executor:
config:
core-pool-size: 20 # 核心线程数
max-pool-size: 50 # 最大线程数
keep-alive-time: 5000 # 线程空闲时间
block-queue-size: 5000 # 队列大小
policy: CallerRunsPolicy # 拒绝策略
# 动态线程池管理配置
dynamic:
thread:
pool:
config:
enabled: true # 状态;true = 开启、false 关闭
host: localhost # redis host
port: 6379 # redis port
# 日志
logging:
level:
root: info
config: classpath:logback-spring.xml
ThreadPoolConfigProperties 线程池配置项
这是一个配置属性类,通过@ConfigurationProperties绑定thread.pool.executor.config前缀的配置。
javascript
@Data
@ConfigurationProperties(prefix = "thread.pool.executor.config", ignoreInvalidFields = true)
public class ThreadPoolConfigProperties {
/** 核心线程数 */
private Integer corePoolSize = 20;
/** 最大线程数 */
private Integer maxPoolSize = 200;
/** 最大等待时间 */
private Long keepAliveTime = 10L;
/** 最大队列数 */
private Integer blockQueueSize = 5000;
/*
* AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。
* DiscardPolicy:直接丢弃任务,但是不会抛出异常
* DiscardOldestPolicy:将最早进入队列的任务删除,之后再尝试加入队列的任务被拒绝
* CallerRunsPolicy:如果任务添加线程池失败,那么主线程自己执行该任务
* */
private String policy = "AbortPolicy";
}
ThreadPoolConfig 线程池配置类
Spring配置类,通过@EnableAsync启用异步任务支持,并绑定ThreadPoolConfigProperties属性。定义了两个线程池Bean(threadPoolExecutor01和threadPoolExecutor02),两者配置相同。线程池参数包括核心线程数、最大线程数、空闲时间、队列类型(LinkedBlockingQueue)及拒绝策略。拒绝策略根据配置动态实例化,未匹配时默认使用AbortPolicy。线程池通过Executors.defaultThreadFactory()创建线程。
javascript
@Slf4j // Lombok注解,自动生成日志对象
@EnableAsync // 启用Spring的异步执行功能
@Configuration // 标识这是一个Spring配置类
@EnableConfigurationProperties(ThreadPoolConfigProperties.class) // 启用配置属性绑定
public class ThreadPoolConfig {
/**
* 创建第一个线程池Bean
* Bean名称:threadPoolExecutor01
* 用途:通过@Qualifier("threadPoolExecutor01")注入使用
*/
@Bean("threadPoolExecutor01")
public ThreadPoolExecutor threadPoolExecutor01(ThreadPoolConfigProperties properties) {
// 根据配置的拒绝策略名称实例化对应的拒绝策略处理器
RejectedExecutionHandler handler;
switch (properties.getPolicy()){
case "AbortPolicy": // 默认策略,拒绝任务并抛出RejectedExecutionException
handler = new ThreadPoolExecutor.AbortPolicy();
break;
case "DiscardPolicy": // 静默丢弃被拒绝的任务,不抛异常
handler = new ThreadPoolExecutor.DiscardPolicy();
break;
case "DiscardOldestPolicy": // 丢弃队列中最老的任务,然后重试执行当前任务
handler = new ThreadPoolExecutor.DiscardOldestPolicy();
break;
case "CallerRunsPolicy": // 由调用线程直接执行被拒绝的任务
handler = new ThreadPoolExecutor.CallerRunsPolicy();
break;
default: // 配置错误时使用默认策略
handler = new ThreadPoolExecutor.AbortPolicy();
break;
}
// 创建并返回ThreadPoolExecutor实例
return new ThreadPoolExecutor(
properties.getCorePoolSize(), // 核心线程数
properties.getMaxPoolSize(), // 最大线程数
properties.getKeepAliveTime(), // 线程空闲存活时间
TimeUnit.SECONDS, // 时间单位:秒
new LinkedBlockingQueue<>(properties.getBlockQueueSize()), // 有界阻塞队列
Executors.defaultThreadFactory(), // 默认线程工厂
handler // 拒绝策略处理器
);
}
/**
* 创建第二个线程池Bean
* Bean名称:threadPoolExecutor02
* 用途:通过@Qualifier("threadPoolExecutor02")注入使用
* 注意:当前实现与threadPoolExecutor01使用相同的配置参数
*/
@Bean("threadPoolExecutor02")
public ThreadPoolExecutor threadPoolExecutor02(ThreadPoolConfigProperties properties) {
// 拒绝策略处理逻辑与第一个线程池相同
RejectedExecutionHandler handler;
switch (properties.getPolicy()){
case "AbortPolicy":
handler = new ThreadPoolExecutor.AbortPolicy();
break;
case "DiscardPolicy":
handler = new ThreadPoolExecutor.DiscardPolicy();
break;
case "DiscardOldestPolicy":
handler = new ThreadPoolExecutor.DiscardOldestPolicy();
break;
case "CallerRunsPolicy":
handler = new ThreadPoolExecutor.CallerRunsPolicy();
break;
default:
handler = new ThreadPoolExecutor.AbortPolicy();
break;
}
// 创建并返回ThreadPoolExecutor实例(参数与第一个线程池相同)
return new ThreadPoolExecutor(
properties.getCorePoolSize(),
properties.getMaxPoolSize(),
properties.getKeepAliveTime(),
TimeUnit.SECONDS,
new LinkedBlockingQueue<>(properties.getBlockQueueSize()),
Executors.defaultThreadFactory(),
handler
);
}
}
Application 主启动类
包含一个ApplicationRunner Bean,用于模拟任务提交到线程池。任务随机生成启动延迟(1-10秒)和执行时间(1-10秒),通过threadPoolExecutor01提交。任务执行时打印延迟和执行时间,若被中断则恢复中断状态。主线程在每次任务提交后随机休眠1-50毫秒,模拟持续的任务流。
javascript
@SpringBootApplication
@Configurable
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
/** 创建一个线程池,用于模拟任务执行 */
@Bean
public ApplicationRunner applicationRunner(ExecutorService threadPoolExecutor01) {
return args -> {
while (true){
// 创建一个随机时间生成器
Random random = new Random();
// 随机时间,用于模拟任务启动延迟
int initialDelay = random.nextInt(10) + 1; // 1到10秒之间
// 随机休眠时间,用于模拟任务执行时间
int sleepTime = random.nextInt(10) + 1; // 1到10秒之间
// 提交任务到线程池
threadPoolExecutor01.submit(() -> {
try {
// 模拟任务启动延迟
TimeUnit.SECONDS.sleep(initialDelay);
System.out.println("Task started after " + initialDelay + " seconds.");
// 模拟任务执行
TimeUnit.SECONDS.sleep(sleepTime);
System.out.println("Task executed for " + sleepTime + " seconds.");
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});
Thread.sleep(random.nextInt(50) + 1);
}
};
}
}
前端页面展示
HTML页面展示动态线程池监控界面,包含以下功能:
自动刷新:通过按钮控制表格数据每3秒自动刷新,显示线程池状态(核心线程数、活跃线程数、队列任务数等)。
数据表格:展示应用名称、线程池名称、队列类型等详细信息,最后一列提供"修改"按钮。
模态框:点击"修改"按钮弹出配置表单,可编辑核心线程数和最大线程数,提交后通过API更新配置。
API交互:使用XMLHttpRequest调用后端接口(如query_thread_pool_list、update_thread_pool_config),处理响应后更新表格或提示操作结果。页面样式采用渐变背景、圆角边框和悬停效果,提升用户体验。
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Dynamic Thread Pool 「动态线程池」</title>
<style>
body {
font-family: 'Segoe UI', Arial, sans-serif;
margin: 0;
padding: 0;
background: linear-gradient(135deg, #eef2f3, #dfe9f3);
}
.container {
max-width: 1200px;
margin: 40px auto;
background: #ffffff;
padding: 30px;
border-radius: 12px;
box-shadow: 0 4px 20px rgba(0,0,0,0.1);
}
h1 {
text-align: center;
margin-bottom: 20px;
font-size: 28px;
color: #333;
}
button {
background-color: #3b82f6;
color: white;
padding: 10px 18px;
margin: 10px 5px 20px 0;
border: none;
border-radius: 6px;
cursor: pointer;
font-size: 14px;
}
button:hover {
background-color: #2563eb;
}
table {
width: 100%;
border-collapse: separate;
border-spacing: 0;
margin-top: 10px;
border-radius: 8px;
overflow: hidden;
}
th {
background-color: #f1f5f9;
padding: 12px;
text-align: left;
font-weight: 600;
border-bottom: 1px solid #e2e8f0;
}
td {
padding: 12px;
border-bottom: 1px solid #f1f5f9;
background-color: #ffffff;
}
tr:nth-child(even) td {
background-color: #f8fafc;
}
.loader {
display: none;
text-align: center;
padding: 10px;
font-size: 16px;
color: #555;
}
/* Modal */
.modal {
display: none;
position: fixed;
z-index: 10;
left: 0;
}
</style>
</head>
<body>
<div class="container">
<h1>Dynamic Thread Pool ------ 动态线程池</h1>
<div class="loader">Loading...</div>
<button id="autoRefreshBtn">自动刷新</button>
<button id="stopAutoRefreshBtn" style="display:none;">停止刷新</button>
<table id="threadPoolList">
<thead>
<tr>
<th>应用名称</th>
<th>线程池名称</th>
<th>核心线程池数</th>
<th>最大线程数</th>
<th>当前活跃线程数</th>
<th>当前池中线程数</th>
<th>队列类型</th>
<th>当前队列任务数</th>
<th>队列剩余容量数</th>
</tr>
</thead>
<tbody>
<!-- Data will be inserted here -->
</tbody>
</table>
</div>
<!-- 模态框(Modal) -->
<div id="myModal" class="modal">
<div class="modal-content">
<span class="close">×</span>
<h2>Thread Pool Configuration</h2>
<form id="configForm">
<label for="appName">应用名称:</label><br>
<input type="text" id="appName" name="appName" readonly><br>
<label for="threadPoolName">线程池名称:</label><br>
<input type="text" id="threadPoolName" name="threadPoolName" readonly><br>
<label for="corePoolSize">核心线程池数:</label><br>
<input type="number" id="corePoolSize" name="corePoolSize"><br>
<label for="maximumPoolSize">最大线程数:</label><br>
<input type="number" id="maximumPoolSize" name="maximumPoolSize"><br>
<button type="button" onclick="updateConfig()">确认修改</button>
</form>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
var loader = document.querySelector('.loader');
var tbody = document.querySelector('#threadPoolList tbody');
var autoRefreshInterval;
var autoRefreshBtn = document.getElementById('autoRefreshBtn');
var stopAutoRefreshBtn = document.getElementById('stopAutoRefreshBtn');
autoRefreshBtn.addEventListener('click', function() {
// 开始自动刷新
if (!autoRefreshInterval) {
autoRefreshInterval = setInterval(fetchThreadPoolList, 3000);
autoRefreshBtn.style.display = 'none';
stopAutoRefreshBtn.style.display = 'inline';
}
});
stopAutoRefreshBtn.addEventListener('click', function() {
// 停止自动刷新
if (autoRefreshInterval) {
clearInterval(autoRefreshInterval);
autoRefreshInterval = null;
autoRefreshBtn.style.display = 'inline';
stopAutoRefreshBtn.style.display = 'none';
}
});
function fetchThreadPoolList() {
loader.style.display = 'block';
var xhr = new XMLHttpRequest();
xhr.open('GET', 'http://localhost:8089/api/v1/dynamic/thread/pool/query_thread_pool_list', true);
xhr.onload = function() {
if (xhr.status >= 200 && xhr.status < 300) {
var response = JSON.parse(xhr.responseText);
if (response.code === "0000" && Array.isArray(response.data)) {
var html = '';
response.data.forEach(function(item) {
html += '<tr>';
html += '<td>' + item.appName + '</td>';
html += '<td>' + item.threadPoolName + '</td>';
html += '<td>' + item.corePoolSize + '</td>';
html += '<td>' + item.maximumPoolSize + '</td>';
html += '<td>' + item.activeCount + '</td>';
html += '<td>' + item.poolSize + '</td>';
html += '<td>' + item.queueType + '</td>';
html += '<td>' + item.queueSize + '</td>';
html += '<td>' + item.remainingCapacity + '</td>';
html += '<td><button onclick="openModal(\'' + item.appName + '\', \'' + item.threadPoolName + '\')">修改</button></td>';
html += '</tr>';
});
tbody.innerHTML = html;
} else {
console.error('The request was successful but the data format is incorrect!');
}
} else {
console.error('The request failed!');
}
loader.style.display = 'none';
};
xhr.onerror = function() {
console.error('The request failed!');
loader.style.display = 'none';
};
xhr.send();
}
fetchThreadPoolList();
});
// 获取模态框元素
var modal = document.getElementById("myModal");
var span = document.getElementsByClassName("close")[0];
// 点击 <span> (x), 关闭模态框
span.onclick = function() {
modal.style.display = "none";
}
// 点击模态框外的区域, 关闭模态框
window.onclick = function(event) {
if (event.target == modal) {
modal.style.display = "none";
}
}
// 打开模态框并填充数据
function openModal(appName, threadPoolName) {
// 发起请求获取线程池配置
var xhr = new XMLHttpRequest();
xhr.open('GET', 'http://localhost:8089/api/v1/dynamic/thread/pool/query_thread_pool_config?appName=' + appName + '&threadPoolName=' + threadPoolName, true);
xhr.onload = function() {
if (xhr.status >= 200 && xhr.status < 300) {
var response = JSON.parse(xhr.responseText);
if (response.code === "0000" && response.data) {
// 填充模态框表单
document.getElementById('appName').value = response.data.appName;
document.getElementById('threadPoolName').value = response.data.threadPoolName;
document.getElementById('corePoolSize').value = response.data.corePoolSize;
document.getElementById('maximumPoolSize').value = response.data.maximumPoolSize;
// ... (填充其他只读字段) ...
modal.style.display = "block";
} else {
console.error('The request was successful but the data format is incorrect!');
}
} else {
console.error('The request failed!');
}
};
xhr.onerror = function() {
console.error('The request failed!');
};
xhr.send();
}
// 更新配置
function updateConfig() {
var appName = document.getElementById('appName').value;
var threadPoolName = document.getElementById('threadPoolName').value;
var corePoolSize = document.getElementById('corePoolSize').value;
var maximumPoolSize = document.getElementById('maximumPoolSize').value;
var xhr = new XMLHttpRequest();
xhr.open('POST', 'http://localhost:8089/api/v1/dynamic/thread/pool/update_thread_pool_config', true);
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.onload = function() {
if (xhr.status >= 200 && xhr.status < 300) {
var response = JSON.parse(xhr.responseText);
if (response.code === "0000") {
alert('Configuration updated successfully!');
modal.style.display = "none";
fetchThreadPoolList(); // 重新加载线程池列表
} else {
alert('Failed to update configuration: ' + response.info);
}
} else {
alert('Failed to update configuration!');
}
};
xhr.onerror = function() {
alert('Failed to update configuration!');
};
xhr.send(JSON.stringify({
appName: appName,
threadPoolName: threadPoolName,
corePoolSize: parseInt(corePoolSize, 10),
maximumPoolSize: parseInt(maximumPoolSize, 10)
}));
}
</script>
</body>
</html>
四、实现效果



五、总结
通过以上代码及实现,我们成功构建了一个功能完备的、简单的动态线程池组件,并且附带前端页面来动态配置与监控线程池。这个组件解决了传统线程池的静态配置难题,赋予了应用更强的弹性和可观测性。
核心价值
对业务开发透明: 接入简单,无侵入。
运维效率提升: 无需重启即可调整参数,快速响应流量变化。
增强稳定性: 实时监控和告警有助于提前发现潜在风险。
可扩展方向
持久化与历史数据: 将数据存入时序数据库(如InfluxDB),支持历史查询和趋势分析。
多注册中心支持: 除了Redis,还可以支持Nacos、Apollo等,增强架构灵活性。
更丰富的告警通道: 集成钉钉、企业微信、短信等告警方式。
权限控制: 为管理端增加完善的RBAC权限管理体系。
官方文档
相关项目参考
Hippo4J:功能非常强大的动态线程池框架,生产级参考。
DynamicTp: 轻量级的动态线程池组件。
希望这篇详细的教程能帮助您理解和实现动态线程池组件。如果您有任何问题或建议,欢迎在评论区留言讨论!