(1)如果堆栈信息明确是应用代码,则证明该线程正在等待资源,一般是大量读取某种资源且该资源采用了资源锁的情况下,线程进入等待状态,等待资源的读取,或者正在等待其他线程的执行等 。
(2)如果发现有大量的线程都正处于这种状态,并且堆栈信息中得知正等待网络读写,这是因为网络阻塞导致线程无法执行,很有可能是一个网络瓶颈的征兆:
网络非常繁忙,几乎消耗了所有的带宽,仍然有大量数据等待网络读写;网络可能是空闲的,但由于路由或防火墙等原因,导致包无法正常到达;所以一定要结合系统的一些性能观察工具进行综合分析,比如netstat统计单位时间的发送包的数量,看是否很明显超过了所在网络带宽的限制;观察CPU的利用率,看系统态的CPU时间是否明显大于用户态的CPU时间 。这些都指向由于网络带宽所限导致的网络瓶颈 。
(3)还有一种常见的情况是该线程在 sleep,等待 sleep 的时间到了,将被唤醒 。
- waiting for monitor entry 或 in Object.wait()Moniter 是Java中用以实现线程之间的互斥与协作的主要手段,它可以看成是对象或者class的锁,每个对象都有,也仅有一个 Monitor 。

文章插图
(1)"Entry Set"里面的线程 。我们称被 synchronized 保护起来的代码段为临界区,对应的代码如下:
synchronized(obj) {} 当一个线程申请进入临界区时,它就进入了 "Entry Set" 队列中,这时候有两种可能性:- 该Monitor不被其他线程拥有,"Entry Set"里面也没有其他等待的线程 。本线程即成为相应类或者对象的Monitor的Owner,执行临界区里面的代码;此时在Thread Dump中显示线程处于 "Runnable" 状态 。
- 该Monitor被其他线程拥有,本线程在 "Entry Set" 队列中等待 。此时在Thread Dump中显示线程处于 "waiting for monity entry" 状态 。临界区的设置是为了保证其内部的代码执行的原子性和完整性,但因为临界区在任何时间只允许线程串行通过,这和我们使用多线程的初衷是相反的 。如果在多线程程序中大量使用synchronized,或者不适当的使用它,会造成大量线程在临界区的入口等待,造成系统的性能大幅下降 。如果在Thread Dump中发现这个情况,应该审视源码并对其进行改进 。
通常来说,当CPU很忙的时候关注 Runnable 状态的线程,反之则关注 waiting for monitor entry 状态的线程 。
JVM线程状态
NEW:每一个线程,在堆内存中都有一个对应的Thread对象 。Thread t = new Thread();当刚刚在堆内存中创建Thread对象,还没有调用t.start()方法之前,线程就处在NEW状态 。在这个状态上,线程与普通的java对象没有什么区别,就仅仅是一个堆内存中的对象 。
RUNNABLE:该状态表示线程具备所有运行条件,在运行队列中准备操作系统的调度,或者正在运行 。这个状态的线程比较正常,但如果线程长时间停留在在这个状态就不正常了,这说明线程运行的时间很长(存在性能问题),或者是线程一直得不得执行的机会(存在线程饥饿的问题) 。
BLOCKED:线程正在等待获取java对象的监视器(也叫内置锁),即线程正在等待进入由synchronized保护的方法或者代码块 。synchronized用来保证原子性,任意时刻最多只能由一个线程进入该临界区域,其他线程只能排队等待 。
WAITING:处在该线程的状态,正在等待某个事件的发生,只有特定的条件满足,才能获得执行机会 。而产生这个特定的事件,通常都是另一个线程 。也就是说,如果不发生特定的事件,那么处在该状态的线程一直等待,不能获取执行的机会 。比如:A线程调用了obj对象的obj.wait()方法,如果没有线程调用obj.notify或obj.notifyAll,那么A线程就没有办法恢复运行;如果A线程调用了LockSupport.park(),没有别的线程调用LockSupport.unpark(A),那么A没有办法恢复运行 。
推荐阅读
- ThreadLocal原理及使用场景大揭秘
- JVM生成的3种文件,你都见过吗?
- 建议收藏 一文深度讲解JVM 内存分析工具 MAT及实践
- Java堆和栈的区别和介绍以及JVM的堆和栈
- java安全编码指南之:Thread API调用规则
- JVM常见线上问题 → CPU 100%、内存泄露 问题排查
- Java性能调优:JVM性能监控常用方法
- 一次完整的JVM堆外内存泄漏故障排查记录
- 使用微软的 ProcDump 调试 Linux 进程
- 什么是线程池?线程池ThreadPoolExecutor使用及其原理又是什么?
