查看原文
其他

怎样了解你的线程在干嘛?

侯树成 Tomcat那些事儿 2021-03-14



人类为了利用好自己的时间,经常会同时做多件事情,比如上厕所时刷手机,开车时听新闻... 对于自己尚且如此,对计算机也不能闲着。为了最大化的提升机器利用率,机器上同时会跑许多的服务,每个服务内,又跑着许多的「线程」。


这些线程奔忙在一线,努力的执行着「老大」交给自己的任务。偶有空闲时间,打个小盹。


经常会有人问类似这样的问题:


Q: 应用程序响应特别慢。不知道是什么原因。

A: 用 jstack 分析下应用的线程在干啥  (具体使用可以参考:Java 线程状态分析工具jstack

Q: 打出来,这该怎么看呢?

A: 找应用具体执行业务逻辑的线程,看状态

Q: 有BLOCKED,有WAITING,不知道怎么看,看到有一段业务好像在取资源

A: ...资源阻塞了


这类问题,我们首先需要了解线程这些状态分别代表什么,这些状态之间,又是如何迁移变换的。


正好最近群里有人在问类似的问题,总结下方便有需要的朋友。


 线程的状态与转换


以 Java 语言为例,在语言初期就提供了创建多线程的能力。这些勤劳的线程,一生会经历多种状态


  • NEW

  • RUNABLE

  • TIMED_WAITING

  • WAITING

  • BLOCKED

  • TERMINATED


当前一个线程的的具体状态,通过Thread的 State 反映。通过这些状态,可以让「老大」了解到线程处于什么阶段。同时,对于我们开发者问题的诊断分析,也有很大的指导意义。



我们来看下面这张图,清晰的展示了线程状态的之间的变换过程。



比如我们较常见的 BLOCKED状态,一般都是在请求锁,在请求资源之类的。比如多线程操作数据库,一个耗时较多的操作,会导致其他对于库的写入也受影响。


再比如操作系统等限制了可以打开的文件句柄数,如果系统里已经打开达到了阈值,但未进行正确的关闭,此时就会产生问题。 这里需要注意的是,一些云服务器,云盘服务,对象存储等,也会对应的占用一个资源。我之前就在使用云服务的对象存储时,排查过类似的关闭问题。


TIME_WAITING 一般则是处于sleep方法,wait方法,join等操作,正在等待时间


RUNNABLE 一般都是你最喜欢看到的,在努力干着活的线程。


如何了解当前线程状态


我们前面提到,为了了解线程当前的执行状态,需要通过 jstack 工具来获取线程的 stack 信息,再从中找到我们关心的线程具体的执行情况。


这里首先需要关注的一点是,对于我们自己的线程,一定要「给他一个名字」。否则,在茫茫的线程海里,你只能欲哭无泪。


对于通过 Thread 创建线程时,可以直接通过构造方法指定名称。 通过「线程池」来获取线程,需要定义自己的ThreadFactory,在其中指定生成的线程名字。


你说我使用 ExecutorService,这个默认生成的线程池,使用的都是默认的 ThreadFactory,结果名字都是这个样子:


DefaultThreadFactory() {
SecurityManager s = System.getSecurityManager();
group = (s != null) ? s.getThreadGroup() :
Thread.currentThread().getThreadGroup();
namePrefix = "pool-" +
poolNumber.getAndIncrement() +
"-thread-";
}


如果线程多的话,全是 pool-x-thread-x 这个样子,你也需要具体定位。


有了具体名字之后,在jstack 生成的信息中,就可以直接定位我们关注的线程了。


比如通过jstack看到这样的信息:



此时,看到显眼的 BLOCKED 再分析是否是代码的问题


当然,在Linux环境中,也可以搭配置 「top」命令来分析。具体可以按这个步骤来操作:


  1. 先用top 命令在机器上分析出当前占用cpu的进程,

  2. 通过top -H -p <pid>  查看进程内各个线程的资源占用

  3. 第一列显示的是这些线程的pid,此时再搭配 jstack生成的线程 stack信息查找对应的内容。需要注意一点,这里得先把pid转换成十六进制,然后再搜索即可,对应我们上面内容中的nid


当然,除此之外,类似于 JConsole、JVisualVM 这些工具中都有关于线程的列表,本质上也和 jstack信息一致,不过是有显眼的颜色状态显示。


通过这些工具,来更详细的分析线程的工作情况,在问题产生的时候,可以做到有的放矢。


PS: 对于 jstack 工具的使用,可以间隔一小段时间多次打印,对比分析,发现问题。


图片来源(https://www.uml-diagrams.org/examples/java-6-thread-state-machine-diagram-example.html)




觉得本文对你有帮助?请分享给更多人支持一下,谢谢

关注『 Tomcat那些事儿  』 ,发现更多精彩文章!了解各种常见问题背后的原理与答案。深入源码,分析细节,内容原创,欢迎关注。



加入知识星球,一起进步



更多精彩内容:

一台机器上安装多个Tomcat 的原理(回复001)

监控Tomcat中的各种数据 (回复002)

启动Tomcat的安全机制(回复003)

乱码问题的原理及解决方式(回复007)

Tomcat 日志工作原理及配置(回复011)

web.xml 解析实现(回复 012)

线程池的原理( 回复 014)

Tomcat 的集群搭建原理与实现 (回复 015)

类加载器的原理 (回复 016)

类找不到等问题 (回复 017)

代码的热替换实现(回复 018)

Tomcat 进程自动退出问题 (回复 019)

为什么总是返回404? (回复 020)

...

PS: 对于一些 Tomcat常见问题,在公众号的【常见问题】菜单中,有需要的朋友欢迎关注查看。

    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存