一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第2天,点击查看活动详情。
前言
上文中提到了如何对线程池的核心参数进行监控。以及文章最后留下的彩蛋ManagementFactory。
本文则讲一下如何依靠ManagementFactory实现对线程状态的监控。
本文关键词: ManagementFactory.getThreadMXBean();
1. 核心思路
ManagementFactory就是用来获取JVM中那些受管理beans的工厂类。它提供了一系列的,用于获取一个或者多个用来表示JVM中platform MXBeans的静态方法。
简单理解,就可以把ManagementFactory当作一些用来获取JVM运行的基础信息的工具,包括:堆的使用信息,GC情况,线程信息等。
2. 实现流程
2.1 ManagementFactory获取线程相关参数
而我们所需要使用的就是下面的方法。
final ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
通过 JDK的源码注释我们知道,ManagementFactory.getThreadMXBean()所返回的就是一组JVM的线程相关的MXBeans。而我们可以通过ThreadMXBean获取当前的线程信息。
2.2 ThreadMXBean获取线程信息
如下:
// 将jvm进程的所有线程及堆栈dump下来
// 切记:我们只是想要当前存活的JVM线程信息即可,不需要获取lock等信息,这里如果设置为true,会挂起执行线程
final ThreadInfo[] threadInfos = threadMXBean.dumpAllThreads(false, false);
2.3 线程监控
2.3.1 线程分组规则
首先,我们从上文中拿到的是所有的线程信息,并不区分线程池的概念;
一般而言,线程名的定义都相对有规律,即前缀一般都是一样的,尤其是线程池中的各线程的线程名称。
所以基于这个角度,我们**可以用名称前缀来对线程进行手动分组**,示例代码如下:
/**
* 保存线程池名称前缀集合
* [这里也可以内置一些线程分组的名称]
*/
private static final Set<String> THREAD_POOL_NAME_PREFIX_SET = Sets.newHashSet();
/**
* 无法分类的线程池组
*/
private static final String DEFAULT = "default";
/**
* JVM中获取的ThreadName,按照分组进行统计。
* 默认以固定前缀作为分组,如果能匹配上就用匹配的前缀分组,否则GROUP = default
* @param threadName 完整线程名
* @return 线程分组
*/
private static String resolveThreadGroup(final String threadName) {
final Optional<String> optional = THREAD_POOL_NAME_PREFIX_SET.stream()
.filter(threadGroup -> threadName.indexOf(threadGroup) == 0)
.findFirst();
if (optional.isPresent()) {
return optional.get();
}
// 通过打印无法分类的线程,后期完善对线程组的名称控制
LOGGER.info("当前线程无法分类:threadName={}", threadName);
return DEFAULT;
}
2.3.2 线程监控分类
线程的状态有6种:NEW, RUNABLE, BLOCKED, WATTING, TIMED_WAITING, TERMINATED。
所以在对于监控线程分组时,我们可以按照“线程名 + 线程状态” 确认一个具体的监控指标。
2.4 完整思路
结合上述所说,对线程状态的整体监控不外乎以下几步:
- 通过
ManagementFactory获取线程MXBean; - 通过
ThreadMXBean获取具体线程信息ThreadInfo[] - 按照规则进行分组,如:线程名称前缀 + 线程状态
Thread.State - 设置周期统计,如:定时任务,定时调度等,用于每隔指定周期获取当前线程状态
- 统计展示,利用统计工具或者图表对线程运行状态进行监控,用于判断当前系统的运行情况。
2.5 总结
常见的线程信息不外乎几种,
- 手动创建的线程,如Thread, Runnable等
- 自定义线程池;
- 系统内置线程池;
- dubbo线程池
通过这两篇,其实我们就解决了前三种的线程状态及参数监控。 后面我们会展开讲一下,如何监控dubbo中的线程状态。
附:
如果文中有描述失误内容,或者没有描述清楚的,可以将问题发我邮箱,harveytuan@163.com, 如果有其他问题,也可以联系我,大家一起共同讨论。
- 愿大家共同进步,共同成长。