点击上方“程序员蜗牛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 <= 0) throw 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 == null) throw 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(5, 20, 60, 1000); }}
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<String, Object> status() { Map<String, Object> 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<String, Object> getMetrics() { 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实战语雀笔记,回复面试、开发手册、有超赞的粉丝福利!