Spring Boot 动态线程池实战方案大公开!

179 阅读3分钟

点击上方“程序员蜗牛g”,选择“设为星标”跟蜗牛哥一起,每天进步一点点程序员蜗牛g大厂程序员一枚 跟蜗牛一起 每天进步一点点32篇原创内容**公众号

如何在 Spring Boot 中构建一套轻量高效的动态线程池方案,并最终展示一个基于 Thymeleaf + Bootstrap 的前端监控界面。

可调整容量的任务队列

文件路径:/src/main/java/com/icoderoad/threadpool/ResizableCapacityLinkedBlockingQueue.java

package com.icoderoad.threadpool;
import java.util.concurrent.*;import java.util.concurrent.locks.Condition;import java.util.concurrent.locks.ReentrantLock;
/** * 可动态修改容量的阻塞队列 */public class ResizableCapacityLinkedBlockingQueue<E> extends LinkedBlockingQueue<E> {    private final ReentrantLock lock = new ReentrantLock();    private final Condition notFull = lock.newCondition();    private volatile int capacity;
    public ResizableCapacityLinkedBlockingQueue(int initialCapacity) {        super(initialCapacity);        this.capacity = initialCapacity;    }
    public void setCapacity(int newCapacity) {        lock.lock();        try {            if (newCapacity <= 0throw new IllegalArgumentException("容量必须大于0");            int oldCapacity = this.capacity;            this.capacity = newCapacity;            if (newCapacity > oldCapacity && size() > 0) {                notFull.signalAll();            }        } finally {            lock.unlock();        }    }
    @Override    public boolean offer(E e) {        if (e == nullthrow new NullPointerException();        lock.lock();        try {            while (size() == capacity) {                if (!notFull.await(10, TimeUnit.MILLISECONDS)) {                    return false;                }            }            return super.offer(e);        } catch (InterruptedException ex) {            Thread.currentThread().interrupt();            return false;        } finally {            lock.unlock();        }    }}

动态线程池执行器

文件路径:/src/main/java/com/icoderoad/threadpool/DynamicThreadPoolExecutor.java

package com.icoderoad.threadpool;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;import java.util.concurrent.ThreadPoolExecutor;import java.util.concurrent.TimeUnit;
/** * 支持动态参数调整的线程池执行器 */public class DynamicThreadPoolExecutor extends ThreadPoolTaskExecutor {
    private volatile int corePoolSize;    private volatile int maxPoolSize;    private volatile long keepAliveSeconds;    private volatile int queueCapacity;    private final ResizableCapacityLinkedBlockingQueue<Runnable> resizableQueue;
    public DynamicThreadPoolExecutor(int corePoolSize, int maxPoolSize,                                     long keepAliveSeconds, int queueCapacity) {        this.corePoolSize = corePoolSize;        this.maxPoolSize = maxPoolSize;        this.keepAliveSeconds = keepAliveSeconds;        this.queueCapacity = queueCapacity;
        this.resizableQueue = new ResizableCapacityLinkedBlockingQueue<>(queueCapacity);        super.setCorePoolSize(corePoolSize);        super.setMaxPoolSize(maxPoolSize);        super.setKeepAliveSeconds((int) keepAliveSeconds);        super.setQueue(resizableQueue);        super.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());    }
    @Override    public ThreadPoolExecutor getThreadPoolExecutor() {        initialize();        return super.getThreadPoolExecutor();    }
    // 动态参数调整方法    public synchronized void setCorePoolSize(int corePoolSize) {        this.corePoolSize = corePoolSize;        super.setCorePoolSize(corePoolSize);    }
    public synchronized void setMaxPoolSize(int maxPoolSize) {        this.maxPoolSize = maxPoolSize;        super.setMaxPoolSize(maxPoolSize);    }
    public synchronized void setKeepAliveSeconds(long keepAliveSeconds) {        this.keepAliveSeconds = keepAliveSeconds;        getThreadPoolExecutor().setKeepAliveTime(keepAliveSeconds, TimeUnit.SECONDS);    }
    public synchronized void setQueueCapacity(int capacity) {        this.queueCapacity = capacity;        resizableQueue.setCapacity(capacity);    }
    // 监控指标    public int getActiveCount() { return getThreadPoolExecutor().getActiveCount(); }    public long getCompletedTaskCount() { return getThreadPoolExecutor().getCompletedTaskCount(); }    public int getQueueSize() { return resizableQueue.size(); }    public double getLoadFactor() {        return maxPoolSize > 0 ? (double) getActiveCount() / maxPoolSize : 0;    }}

Spring Boot 配置与集成

文件路径:/src/main/java/com/icoderoad/config/ThreadPoolConfig.java

package com.icoderoad.config;
import com.icoderoad.threadpool.DynamicThreadPoolExecutor;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;
@Configurationpublic class ThreadPoolConfig {    @Bean    public DynamicThreadPoolExecutor dynamicThreadPoolExecutor() {        return new DynamicThreadPoolExecutor(520601000);    }}

Actuator 端点(可选)

文件路径:/src/main/java/com/icoderoad/monitor/ThreadPoolEndpoint.java

package com.icoderoad.monitor;
import com.icoderoad.threadpool.DynamicThreadPoolExecutor;import org.springframework.boot.actuate.endpoint.annotation.*;import org.springframework.stereotype.Component;
import java.util.HashMap;import java.util.Map;
@Component@Endpoint(id = "threadpool")public class ThreadPoolEndpoint {
    private final DynamicThreadPoolExecutor executor;
    public ThreadPoolEndpoint(DynamicThreadPoolExecutor executor) {        this.executor = executor;    }
    @ReadOperation    public Map<StringObjectstatus() {        Map<StringObject> metrics = new HashMap<>();        metrics.put("active", executor.getActiveCount());        metrics.put("completed", executor.getCompletedTaskCount());        metrics.put("queue", executor.getQueueSize());        metrics.put("load", executor.getLoadFactor());        return metrics;    }
    @WriteOperation    public String adjust(Integer corePoolSize, Integer maxPoolSize,                         Long keepAliveSeconds, Integer queueCapacity) {        if (corePoolSize != null) executor.setCorePoolSize(corePoolSize);        if (maxPoolSize != null) executor.setMaxPoolSize(maxPoolSize);        if (keepAliveSeconds != null) executor.setKeepAliveSeconds(keepAliveSeconds);        if (queueCapacity != null) executor.setQueueCapacity(queueCapacity);        return "调整完成";    }}

使用示例

package com.icoderoad.demo;
import com.icoderoad.threadpool.DynamicThreadPoolExecutor;import java.util.Map;
public class TaskHelper {
    private final DynamicThreadPoolExecutor executor;
    public TaskHelper(DynamicThreadPoolExecutor executor) {        this.executor = executor;    }
    public void submitTask(Runnable task) {        executor.execute(task);    }
    public Map<StringObjectgetMetrics() {        return Map.of(                "active", executor.getActiveCount(),                "queue", executor.getQueueSize(),                "load"String.format("%.2f%%", executor.getLoadFactor() * 100)        );    }}

部署与配置

在 application.yml 中开启自定义端点:

management:  endpoints:    web:      exposure:        include: health,info,threadpoolendpoint:  threadpool:    enabled: true
spring:  cloud:    config:      uri: http://config-server:8888

前端监控界面示例(Thymeleaf + Bootstrap)

threadpool.html 页面,用于展示线程池的运行指标。

文件路径:/src/main/resources/templates/threadpool.html

<!DOCTYPE html><html xmlns:th="http://www.thymeleaf.org"><head>    <title>线程池监控</title>    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet"></head><body class="p-4"><div class="container">    <h2 class="mb-4">动态线程池监控</h2>    <table class="table table-bordered text-center">        <thead class="table-dark">        <tr>            <th>核心线程数</th>            <th>最大线程数</th>            <th>活跃线程数</th>            <th>已完成任务</th>            <th>队列大小</th>            <th>负载因子</th>        </tr>        </thead>        <tbody id="metrics-body">        <tr>            <td id="corePoolSize">-</td>            <td id="maxPoolSize">-</td>            <td id="active">-</td>            <td id="completed">-</td>            <td id="queue">-</td>            <td id="load">-</td>        </tr>        </tbody>    </table></div>
<script>    async function fetchMetrics() {        const response = await fetch('/actuator/threadpool');        const data = await response.json();        document.getElementById("active").textContent = data.active;        document.getElementById("completed").textContent = data.completed;        document.getElementById("queue").textContent = data.queue;        document.getElementById("load").textContent = (data.load * 100).toFixed(2) + "%";        // 注意:核心线程数和最大线程数可以通过配置中心或写入到端点中扩展        document.getElementById("corePoolSize").textContent = "动态配置";        document.getElementById("maxPoolSize").textContent = "动态配置";    }
    setInterval(fetchMetrics, 2000);    fetchMetrics();</script></body></html>

该页面每 2 秒刷新一次线程池运行指标,配合 Actuator 提供的数据,能够直观展示系统的运行状态。

如果这篇文章对您有所帮助,或者有所启发的话,求一键三连:点赞、转发、在看。

关注公众号:woniuxgg,在公众号中回复:笔记  就可以获得蜗牛为你精心准备的java实战语雀笔记,回复面试、开发手册、有超赞的粉丝福利!