语法
[service@10-176-221-255.drp-project-service-marketing2c.dgdev01 bin]$ ./jstack -h
Usage:
jstack [-l] <pid>
(to connect to running process)
jstack -F [-m] [-l] <pid>
(to connect to a hung process)
jstack [-m] [-l] <executable> <core>
(to connect to a core file)
jstack [-m] [-l] [server_id@]<remote server IP or hostname>
(to connect to a remote debug server)
Options:
-F to force a thread dump. Use when jstack <pid> does not respond (process is hung)
-m to print both java and native frames (mixed mode)
-l long listing. Prints additional information about locks
-h or -help to print this help message
如:jstack -l 打印线程堆栈跟踪信息
jstack -F 当jvm无响应时,可强制打印线程堆栈
线程堆栈字段说明:
- ConsumeMessageThread_46: 线程名称
- #316 线程编号
- prio=5 优先级,默认:5
- os_prio=0 表示操作系统级别的优先级
- tid=0x00007f6bbc00b000 JVM内部线程的唯一标识(通过java.lang.Thread.getId()获取,通常用自增方式实现)
- nid=0x2a4 对应操作系统下的tid线程号,也就是前面转化的16进制数字
pid --> nid: printf ‘0x%x’ - 线程状态 new、runnable、blocked、waiting、time_waiting、terminated
0x00007f6b069e0000 对象的内存地址,通过jvm内存查看工具,能够看出线程在哪个对象上等待
线程状态:
(trouble shooting时重点关注标黄的)
-
NEW A thread that has not yet started is in this state.(线程对象创建后,还没没有开始执行的线程处于这种状态)
-
RUNNABLE A thread executing in the Java virtual machine is in this state(在JVM中执行的线程处于这种状态,分Ready和Running)
-
Blocked A thread that is blocked waiting for a monitor lock is in this state.
线程阻塞,是指当前线程执行过程中,所需要的资源长时间等待却一直未能获取到(比如“锁”),被容器的线程管理器标识为阻塞状态,可以理解为等待资源超时的线程 -
WAITING A thread that is waiting indefinitely for another thread to perform a particular action is in this state(等待另一个线程执行某些特别操作的线程处于这种状态。)
-
TIMED_WAINTING A thread that is waiting for another thread to perform an action for up to a specified waiting time is in this state( 等待另一个线程执行某些特别操作的线程(有时间限制)处于这种状态)。线程调用如下方法都会进入TIMED_TAITING状态。
• Thread.sleep
• Object.wait with timeout
• Thread.join with timeout
• LockSupport.parkNanos
• LockSupport.parkUntil -
Waiting on condition 该状态出现在线程等待某个条件的发生。最常见的情况是线程在等待网络的读写,比如当网络数据没有准备好读时,线程处于这种等待状态。而一旦有数据准备好读之后,线程会重新激活,读取并处理数据。
如果发现有大量的线程都在处在 Wait on condition,从线程堆栈看,正等待网络读写,这可能是一个网络瓶颈的征兆,因为网络阻塞导致线程无法执行,原因有两种:一种情况是网络非常忙,几 乎消耗了所有的带宽,仍然有大量数据等待网络读写;另一种情况也可能是网络空闲,但由于路由等问题,导致包无法正常的到达。
另外一种出现 Wait on condition的常见情况是该线程在 sleep,等待 sleep的时间到了时候,将被唤醒。 -
Waiting on monitor entry 表示线程正在获取锁。Monitor是 Java中用以实现线程之间的互斥与协作的主要手段,它可以看成是对象或者 Class的锁。每一个对象都有,也仅有一个 monitor
TERMINATED A thread that has exited is in this state (一个已经执行完毕的线程处于这种状态)
线程状态流转
异常定位思路:
1. 连续获取几个线程堆栈,追加输出到同一个文件
2. 先看看有没有死锁
grep -i "deadlock" aa.tdump
3. 在看看有没有blocked的线程,根据等待的资源查看是哪个线程hold住了该资源
类似:
- locked <0x000000066e1a71b8> (a io.netty.channel.nio.SelectedSelectionKeySet)
grep -i "blocked" aa.tdump
4. 看看各个线程状态的统计分布
当有大量的"Waiting on monitor entry"或者“blocked"的线程时,一般都有问题,存在优化空间
常用命令:
#每隔5秒获取打印一次堆栈信息,打印3次。
for i in {1..3};do jstack -l 244 >> /tmp/$ip_$(date +%Y%m%d_%T).tdump;i+=1;sleep 5;done
#统计各个状态的线程数
grep -i "nid=" -A 1 bb.tdump | grep "java.lang.Thread.State" | awk -F ":" '{state[$2]++}END{for(i in state){print i,state[i]}}'