一、Thread Dump日志的线程信息
"resin-22129" 线程名称:如果使用 java.lang.Thread 类生成一个线程的时候,线程名称为 Thread-(数字) 的形式,这里是resin生成的线程;
daemon 线程类型:线程分为守护线程 (daemon) 和非守护线程 (non-daemon) 两种,通常都是守护线程;
prio=10 线程优先级:默认为5,数字越大优先级越高;
tid=0x00007fbe5c34e000 JVM线程的id:JVM内部线程的唯一标识,通过 java.lang.Thread.getId()获取,通常用自增的方式实现;
nid=0x4cb1 系统线程id:对应的系统线程id(Native Thread ID),可以通过 top 命令进行查看,现场id是十六进制的形式;
waiting on condition 系统线程状态:这里是系统的线程状态,具体的含义见下面 系统线程状态 部分;
[0x00007fbe4ff7c000] 起始栈地址:线程堆栈调用的其实内存地址;
java.lang.Thread.State: WAITING (parking) JVM线程状态:这里标明了线程在代码级别的状态,详细的内容见下面的 JVM线程运行状态 部分。
线程调用栈信息:下面就是当前线程调用的详细栈信息,用于代码的分析。堆栈信息应该从下向上解读,因为程序调用的顺序是从下向上的。
二、系统线程的状态,以及各个状态代表的含义及其造成的原因
重点关注:deadlock\waiting on condition\Waiting on monitor entry\Blocked(重点关注)
Deadlock
死锁线程,一般指多个线程调用期间进入了相互资源占用,导致一直等待无法释放的情况。
runnable
一般指该线程正在执行状态中,该线程占用了资源,正在处理某个操作,如通过SQL语句查询数据库、对某个文件进行写入等
Waiting on condition
等待某个资源或条件发生来唤醒自己。具体需要结合jstacktrace来分析,比如线程正在sleep,网络读写繁忙而等待
线程正处于等待资源或等待某个条件的发生,具体的原因需要结合下面堆栈信息进行分析。
(1)如果堆栈信息明确是应用代码,则证明该线程正在等待资源,一般是大量读取某种资源且该资源采用了资源锁的情况下,线程进入等待状态,等待资源的读取,或者正在等待其他线程的执行等。
(2)如果发现有大量的线程都正处于这种状态,并且堆栈信息中得知正等待网络读写,这是因为网络阻塞导致线程无法执行,很有可能是一个网络瓶颈的征兆:
网络非常繁忙,几乎消耗了所有的带宽,仍然有大量数据等待网络读写;
网络可能是空闲的,但由于路由或防火墙等原因,导致包无法正常到达;
所以一定要结合系统的一些性能观察工具进行综合分析,比如netstat统计单位时间的发送包的数量,看是否很明显超过了所在网络带宽的限制;观察CPU的利用率,看系统态的CPU时间是否明显大于用户态的CPU时间。这些都指向由于网络带宽所限导致的网络瓶颈。
(3)还有一种常见的情况是该线程在 sleep,等待 sleep 的时间到了,将被唤醒。
WAITING
某一等待线程的线程状态。线程正在无期限地等待另一个线程来执行某一个特定的操作,线程因为调用下面的方法之一而处于等待状态:
不带超时的 Object.wait 方法,日志中显示为 java.lang.Thread.State: WAITING (on object monitor)
不带超时的 Thread.join 方法
LockSupport.park 方法,日志中显示为 java.lang.Thread.State: WAITING (parking)
Waiting on monitor entry:在等待获取锁
在多线程的 JAVA程序中,实现线程之间的同步,就要说说Monitor。Monitor是Java中用以实现线程之间的互斥与协作的主要手段,它可以看成是对象或者 Class的锁。每一个对象都有,也仅有一个 monitor。下面这个图,描述了线程和 Monitor之间关系,以及线程的状态转换图:
从图中可以看出,每个 Monitor在某个时刻,只能被一个线程拥有,该线程就是 “Active Thread”,而其它线程都是 “Waiting Thread”,分别在两个队列 “ Entry Set”和 “Wait Set”里面等候。在 “Entry Set”中等待的线程状态是 “Waiting for monitorentry”,而在 “Wait Set”中等待的线程状态是“in Object.wait()”。
Blocked:阻塞
如果说系统的cpu耗的高,那么肯定是线程执行有死循环,那么此时要关注下Runable状态。
三、补充一次线上问题
具体问题如下:
"hystrix-hestia-pay-gateway-pre-27" #1937 daemon prio=5 os_prio=0 tid=0x00007f3b78067800 nid=0x239e waiting on condition [0x00007f3b1e899000]
java.lang.Thread.State: WAITING (parking)
at sun.misc.Unsafe.park(Native Method)
- parking to wait for <0x00000000844d1ac8> (a java.util.concurrent.SynchronousQueue$TransferStack)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
at java.util.concurrent.SynchronousQueue$TransferStack.awaitFulfill(SynchronousQueue.java:458)
at java.util.concurrent.SynchronousQueue$TransferStack.transfer(SynchronousQueue.java:362)
at java.util.concurrent.SynchronousQueue.take(SynchronousQueue.java:924)
at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1074)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1134)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
"hystrix-hestia-pay-gateway-pre-26" #1934 daemon prio=5 os_prio=0 tid=0x00007f3b80827000 nid=0x2399 waiting on condition [0x00007f3b1e91b000]
java.lang.Thread.State: WAITING (parking)
at sun.misc.Unsafe.park(Native Method)
- parking to wait for <0x00000000844d1ac8> (a java.util.concurrent.SynchronousQueue$TransferStack)
由于出现了大量的waiting on condition ,这是我们测试环境出现的问题,主要看parking to wait for <0x00000000844d1ac8>,两个地址是一样的0x00000000844d1ac8
jstack [进程pid]|grep -A 100 [线程pid]
查看现在的每一个java进程的线程数
echo 'pid--number' ;for pid in `ps ax | grep java | grep -v grep | awk '{print $1}'` ; do echo -n ${pid}--;pstree -p $pid | wc -l; done
查看当前所有线程数量
pstree -p|wc -l
额外介绍一个查找最消耗cpu的java线程,jps 找到java进程PID
命令:ps -mp pid -o THREAD,tid,time 或者 ps -Lfppid