借鉴javaguide中的《如何设计一个动态线程池?》
1、代码实践
获取线程池的参数使用的是@endpoint端点
1. 注解说明
@Endpoint
:用于标记一个类为自定义 Actuator 端点。id
:端点的唯一标识符,用于访问端点时的 URL 路径。
- 例如,
id = "myendpoint"
时,默认路径为/actuator/myendpoint
。
2. 方法注解
@Endpoint
提供了三种注解,分别对应不同类型的 HTTP 方法:
@ReadOperation
:映射到 HTTPGET
请求,主要用于获取数据。@WriteOperation
:映射到 HTTPPOST
请求,主要用于修改数据。@DeleteOperation
:映射到 HTTPDELETE
请求,主要用于删除资源。3.调用方法(示例)
GET 请求:获取线程池状态
curl -X GET http://localhost:8080/actuator/threadpool
POST 请求:更新线程池配置
curl -X POST http://localhost:8080/actuator/threadpool \
-H "Content-Type: application/json" \
-d '{"corePoolSize": 15, "maxPoolSize": 30}'
DELETE 请求:重置线程池配置curl -X DELETE http://localhost:8080/actuator/threadpool
pom.xml加入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
application.yml中加入
management:
endpoints:
web:
exposure:
include: "*"
依次创建以下文件并写入代码
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class MonitorThreadPool extends ThreadPoolExecutor {
public MonitorThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, new LinkedBlockingQueue<>(100));
}
public int getCorePoolSize() {
return super.getCorePoolSize();
}
public int getMaximumPoolSize() {
return super.getMaximumPoolSize();
}
public int getActiveCount() {
return super.getActiveCount();
}
public long getCompletedTaskCount() {
return super.getCompletedTaskCount();
}
public long getTaskCount() {
return super.getTaskCount();
}
}
@Component
@Endpoint(id = "threadpool")
public class ThreadPoolEndpoint {
@Autowired
private ThreadPoolManager threadPoolManager;
@ReadOperation
public Map<String, Object> threadPoolsMetric() {
Map<String, Object> metricMap = new HashMap<>();
Map<String, Map<String, Object>> threadPools = new HashMap<>();
threadPoolManager.getThreadPoolExecutorMap().forEach((name, executor) -> {
Map<String, Object> poolInfo = new HashMap<>();
poolInfo.put("coreSize", executor.getCorePoolSize());
poolInfo.put("maxSize", executor.getMaximumPoolSize());
poolInfo.put("activeCount", executor.getActiveCount());
poolInfo.put("taskCount", executor.getTaskCount());
poolInfo.put("completedTaskCount", executor.getCompletedTaskCount());
threadPools.put(name, poolInfo);
});
metricMap.put("threadPools", threadPools);
return metricMap;
}
}
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
@Component
public class ThreadPoolManager {
private final Map<String, MonitorThreadPool> threadPoolExecutorMap = new HashMap<>();
public ThreadPoolManager() {
threadPoolExecutorMap.put("threadPool1", createMonitorThreadPool(10, 20, 60));
threadPoolExecutorMap.put("threadPool2", createMonitorThreadPool(5, 15, 30));
}
private MonitorThreadPool createMonitorThreadPool(int corePoolSize, int maxPoolSize, long keepAliveTime) {
return new MonitorThreadPool(corePoolSize, maxPoolSize, keepAliveTime, TimeUnit.SECONDS);
}
public Map<String, MonitorThreadPool> getThreadPoolExecutorMap() {
return threadPoolExecutorMap;
}
public MonitorThreadPool getThreadPoolExecutor(String name) {
return threadPoolExecutorMap.get(name);
}
public void addThreadPool(String name, int corePoolSize, int maxPoolSize, long keepAliveTime) {
if (threadPoolExecutorMap.containsKey(name)) {
throw new IllegalArgumentException("ThreadPool with name " + name + " already exists.");
}
threadPoolExecutorMap.put(name, createMonitorThreadPool(corePoolSize, maxPoolSize, keepAliveTime));
}
public void removeThreadPool(String name) {
MonitorThreadPool executor = threadPoolExecutorMap.remove(name);
if (executor != null) {
executor.shutdown();
}
}
}
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class ThreadPoolApplication {
public static void main(String[] args) {
SpringApplication.run(ThreadPoolApplication.class, args);
}
}
2、测试代码
在网页输入localhost:8080/actuator/threadpool
结果显示
这里只获得了动态线程池的参数,如果要可视化可以使用 dynamic-tp