【Java动态线程池】Redis监控+动态调参

一、动态线程池需求分析与原理

[1.1 核心需求](#1.1 核心需求)

[1.2 架构总览](#1.2 架构总览)

[1.3 核心原理](#1.3 核心原理)

[1.4 参数动态性总结表](#1.4 参数动态性总结表)

二、开发环境配置

三、代码实现

spring-boot-starter模块

Admin管理端模块

Test模块

前端页面展示

四、实现效果

五、总结


前言

线程池(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">&times;</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权限管理体系。

官方文档

Spring Boot Reference Guide

Redis Documentation

相关项目参考

Hippo4J:功能非常强大的动态线程池框架,生产级参考。

DynamicTp: 轻量级的动态线程池组件。

希望这篇详细的教程能帮助您理解和实现动态线程池组件。如果您有任何问题或建议,欢迎在评论区留言讨论!

相关推荐
豆奶特浓61 小时前
Java面试模拟:当搞笑程序员谢飞机遇到电商秒杀与AIGC客服场景
java·spring boot·微服务·面试·aigc·高并发·电商
明洞日记1 小时前
【设计模式手册013】命令模式 - 请求封装的优雅之道
java·设计模式·命令模式
方白羽2 小时前
Android多层嵌套RecyclerView滚动
android·java·kotlin
ModestCoder_2 小时前
ROS Bag与导航数据集技术指南
开发语言·人工智能·自然语言处理·机器人·具身智能
卡提西亚2 小时前
C++笔记-34-map/multimap容器
开发语言·c++·笔记
2***B4492 小时前
C++在金融中的QuantLibXL
开发语言·c++·金融
uup2 小时前
Java 中 ArrayList 线程安全问题
java
uup2 小时前
Java 中日期格式化的潜在问题
java