在一个分布式系统中,一般都会有一个或多个固定的线程池来处理我们提交的任务。很多时候我们需要关注线程池的运行情况,根据情况来调整我们线程池参数。我们可以使用Actuator 很简单的完成这件事情。
pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
自定义一个监控线程池的 HealthContributor
/**
* @author lyy
*/
public class MyThreadPollHealthContributor implements HealthIndicator {
private ThreadPoolExecutor executor;
public MyThreadPollHealthContributor(ThreadPoolExecutor executor) {
this.executor = executor;
}
@Override
public Health health() {
//核心线程数
int corePoolSize = executor.getCorePoolSize();
//活跃线程数
int activeCount = executor.getActiveCount();
//完成的任务数
long completedTaskCount = executor.getCompletedTaskCount();
//线程数历史高峰线
int largestPoolSize = executor.getLargestPoolSize();
//当前池中线程数
int poolSize = executor.getPoolSize();
BlockingQueue<Runnable> queue = executor.getQueue();
//队列剩余空间数
int remainingCapacity = queue.remainingCapacity();
//队列中的任务
int queueSize = queue.size();
//最大线程数
int maximumPoolSize = executor.getMaximumPoolSize();
//如果当前活跃线程数 大于 80%的最大线程数,就认证是down
double rate = BigDecimal.valueOf(activeCount)
.divide(BigDecimal.valueOf(maximumPoolSize), 2, BigDecimal.ROUND_HALF_UP)
.doubleValue();
Map<String, Object> infoMap = new HashMap<String, Object>();
infoMap.put("核心线程数",corePoolSize);
infoMap.put("当前活跃线程数", activeCount);
infoMap.put("线程峰值", largestPoolSize);
infoMap.put("完成的任务数", completedTaskCount);
infoMap.put("当前池中线程数", poolSize);
infoMap.put("队列剩余大小", remainingCapacity);
infoMap.put("当前队列中的任务数", queueSize);
infoMap.put("设置最大线程数", maximumPoolSize);
if(rate > 0.8) {
return Health.down().withDetails(infoMap).build();
}else {
return Health.up().withDetails(infoMap).build();
}
}
我们可以监控多个对象,自定义一个 CompositeHealthContributor
/**
* @author lyy
* 线程池
*/
public class ThreadPoolConfig {
public static final ThreadPoolExecutor executor =
new ThreadPoolExecutor(5, 10, 1, TimeUnit.MINUTES, new ArrayBlockingQueue<Runnable>(100));
}
/**
* @author lyy
*/
@Component
public class MyCompositeHealthContributor implements CompositeHealthContributor {
private Map<String, HealthContributor> map = new HashMap<String, HealthContributor>();
@PostConstruct
public void init() {
MyThreadPollHealthContributor threadPool = new MyThreadPollHealthContributor(ThreadPoolConfig.executor);
map.put("threadPoll", threadPool);
addTask();
}
@Override
public HealthContributor getContributor(String name) {
return map.get(name);
}
@Override
public Iterator<NamedContributor<HealthContributor>> iterator() {
List<NamedContributor<HealthContributor>> contributors = new ArrayList<NamedContributor<HealthContributor>>();
map.forEach((name,c) ->{
contributors.add(NamedContributor.of(name, c));
});
return contributors.iterator();
}
/**
* 模拟添加任务
*/
public void addTask() {
AtomicLong finishTaskNum = new AtomicLong();
new Thread(() ->{
while(true) {
try {
ThreadPoolConfig.executor.execute(() ->{
try {
TimeUnit.SECONDS.sleep(ThreadLocalRandom.current().nextInt(10,40));
System.out.println("完成任务.."+ finishTaskNum.getAndIncrement());
} catch (Exception e) {
e.printStackTrace();
}
});
TimeUnit.SECONDS.sleep(1);
} catch (Exception e2) {
}
}
}).start();
}
}
application.yml
management:
endpoints:
web:
exposure:
include: "*"
endpoint:
health:
show-details: always
ok,启动项目 访问 http://localhost:8080/actuator/health 就可以看到线程池的相关信息了