Java命令:jstack — 获取线程dump信息

一、命令介绍

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)  //连接dump的文件
    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命令,首先我们要先找到要查看的进程ID,命令如下:

$ ps -ef | grep --color "com.javaagent.Main"

结果如下:
在这里插入图片描述
红框中即为进程ID。

实例一:jstack查看输出

命令如下:

$ jstack -l 69239

输出结果:

$ jstack -l 69239

2020-03-03 15:16:07
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.121-b13 mixed mode):

"Attach Listener" #13 daemon prio=9 os_prio=31 tid=0x00007f9242141000 nid=0x5707 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

   Locked ownable synchronizers:
	- None

"ThreadTest" #11 prio=5 os_prio=31 tid=0x00007f9242140800 nid=0x5503 waiting on condition [0x00007000013d2000]
   java.lang.Thread.State: TIMED_WAITING (sleeping)
	at java.lang.Thread.sleep(Native Method)
	at com.javaagent.Main$2.run(Main.java:64)
	at java.lang.Thread.run(Thread.java:745)

   Locked ownable synchronizers:
	- None

...

"ThreadTest_2" #10 prio=5 os_prio=31 tid=0x00007f9242100000 nid=0x5303 in Object.wait() [0x00007000012cf000]
   java.lang.Thread.State: WAITING (on object monitor)
	at java.lang.Object.wait(Native Method)
	- waiting on <0x0000000795856e18> (a java.lang.Object)
	at java.lang.Object.wait(Object.java:502)
	at com.javaagent.Main$1.run(Main.java:41)
	- locked <0x0000000795856e18> (a java.lang.Object)
	at java.lang.Thread.run(Thread.java:745)

   Locked ownable synchronizers:
	- None

"Finalizer" #3 daemon prio=8 os_prio=31 tid=0x00007f9242004000 nid=0x3003 in Object.wait() [0x000070000092e000]
   java.lang.Thread.State: WAITING (on object monitor)
	at java.lang.Object.wait(Native Method)
	- waiting on <0x0000000795588ec8> (a java.lang.ref.ReferenceQueue$Lock)
	at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:143)
	- locked <0x0000000795588ec8> (a java.lang.ref.ReferenceQueue$Lock)
	at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:164)
	at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:209)

   Locked ownable synchronizers:
	- None

"VM Thread" os_prio=31 tid=0x00007f9243841800 nid=0x2c03 runnable 

"GC task thread#0 (ParallelGC)" os_prio=31 tid=0x00007f9243810800 nid=0x2403 runnable 

"GC task thread#1 (ParallelGC)" os_prio=31 tid=0x00007f9243811000 nid=0x2603 runnable 

"GC task thread#2 (ParallelGC)" os_prio=31 tid=0x00007f9243811800 nid=0x2803 runnable 

"GC task thread#3 (ParallelGC)" os_prio=31 tid=0x00007f9243812800 nid=0x2a03 runnable 

"VM Periodic Task Thread" os_prio=31 tid=0x00007f9243805000 nid=0x4d03 waiting on condition 

JNI global references: 25

实例二:jstack统计线程数

命令如下:

$ jstack -l 69239 | grep 'java.lang.Thread.State' | wc -l

输出结果:

12

实例三:jstack检测死锁

死锁代码:

package com.javaagent.thread;

public class DieThread implements Runnable {

    public static Object obj1=new Object();
    public static Object obj2=new Object();

    private boolean flag;

    public DieThread(boolean bl){
        flag = bl;
    }

    @Override
    public void run() {
        if(flag) {
            while(true) {
                synchronized(obj1) {
                    System.out.println(Thread.currentThread().getName()+"....if...obj1...");
                    synchronized(obj2) {
                        System.out.println(Thread.currentThread().getName()+".....if.....obj2.....");

                    }
                }
            }
        }
        else {
            while(true){
                synchronized(obj2) {
                    System.out.println(Thread.currentThread().getName()+"....else...obj2...");
                    synchronized(obj1) {
                        System.out.println(Thread.currentThread().getName()+".....else.....obj1.....");

                    }
                }
            }
        }
    }
}


public class Main {

    public static void main(String[] args){
        DieThread d1=new DieThread(true);
        DieThread d2=new DieThread(false);
        final Thread t1 = new Thread(d1);
        final Thread t2 = new Thread(d2);
        t1.setName("DieThread_1");
        t2.setName("DieThread_2");
        t1.start();
        t2.start();
    }
}

命令如下:

$ jstack -l 69239

死锁日志:

"DieThread_2" #11 prio=5 os_prio=31 tid=0x00007fc761896000 nid=0x5503 waiting for monitor entry [0x000070000134f000]
   java.lang.Thread.State: BLOCKED (on object monitor)
	at com.javaagent.thread.DieThread.run(DieThread.java:32)
	- waiting to lock <0x000000079586a768> (a java.lang.Object)
	- locked <0x000000079586a778> (a java.lang.Object)
	at java.lang.Thread.run(Thread.java:745)

   Locked ownable synchronizers:
	- None

"DieThread_1" #10 prio=5 os_prio=31 tid=0x00007fc7610dd800 nid=0x5307 waiting for monitor entry [0x000070000124c000]
   java.lang.Thread.State: BLOCKED (on object monitor)
	at com.javaagent.thread.DieThread.run(DieThread.java:21)
	- waiting to lock <0x000000079586a778> (a java.lang.Object)
	- locked <0x000000079586a768> (a java.lang.Object)
	at java.lang.Thread.run(Thread.java:745)

   Locked ownable synchronizers:
	- None

Found one Java-level deadlock:
=============================
"DieThread_2":
  waiting to lock monitor 0x00007fc7620421f8 (object 0x000000079586a768, a java.lang.Object),
  which is held by "DieThread_1"
"DieThread_1":
  waiting to lock monitor 0x00007fc762042358 (object 0x000000079586a778, a java.lang.Object),
  which is held by "DieThread_2"

Java stack information for the threads listed above:
===================================================
"DieThread_2":
	at com.javaagent.thread.DieThread.run(DieThread.java:32)
	- waiting to lock <0x000000079586a768> (a java.lang.Object)
	- locked <0x000000079586a778> (a java.lang.Object)
	at java.lang.Thread.run(Thread.java:745)
"DieThread_1":
	at com.javaagent.thread.DieThread.run(DieThread.java:21)
	- waiting to lock <0x000000079586a778> (a java.lang.Object)
	- locked <0x000000079586a768> (a java.lang.Object)
	at java.lang.Thread.run(Thread.java:745)

Found 1 deadlock.

实例四:jstack检测CPU高

步骤一:查看cpu占用高进程

输入命令:

$ top

输出结果:

top - 07:50:58 up 53 days, 23:38,  2 users,  load average: 0.00, 0.00, 0.00
Tasks: 113 total,   1 running, 112 sleeping,   0 stopped,   0 zombie
Cpu(s):  0.2%us,  0.2%sy,  0.0%ni, 99.7%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
Mem:   7771904k total,  1770024k used,  6001880k free,   160496k buffers
Swap:  1048572k total,        0k used,  1048572k free,   844572k cached

  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND                                                    
 9075 root      20   0 19468 1540 1116 R  0.7  0.0   0:00.02 top                                                         
 1177 root      20   0  240m 4252 1688 S  0.3  0.1 176:47.24 oneagentwatchdo                                             
 1546 zabbix    20   0 81212 1616  728 S  0.3  0.0  28:12.55 zabbix_agentd                                               
 4433 root      20   0 4495m 566m  14m S  0.3  7.5  61:48.80 java                                                        
    1 root      20   0 23804 1772 1364 S  0.0  0.0   0:00.82 init                                                        
    2 root      20   0     0    0    0 S  0.0  0.0   0:00.00 kthreadd                                                    
    3 root      RT   0     0    0    0 S  0.0  0.0   0:03.89 migration/0                                                 
    4 root      20   0     0    0    0 S  0.0  0.0   0:16.97 ksoftirqd/0

步骤二:查看cpu占用高线程

输入命令:

$ top -H -p 4433

输出结果:

top - 07:52:22 up 53 days, 23:40,  2 users,  load average: 0.08, 0.02, 0.01
Tasks:  62 total,   0 running,  62 sleeping,   0 stopped,   0 zombie
Cpu(s):  0.1%us,  0.1%sy,  0.0%ni, 99.7%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
Mem:   7771904k total,  1770296k used,  6001608k free,   160496k buffers
Swap:  1048572k total,        0k used,  1048572k free,   844576k cached

  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND                                                    
 4433 root      20   0 4495m 566m  14m S  0.0  7.5   0:00.00 java                                                        
 4434 root      20   0 4495m 566m  14m S  0.0  7.5   0:09.75 java                                                        
 4435 root      20   0 4495m 566m  14m S  0.0  7.5   0:00.99 java                                                        
 4436 root      20   0 4495m 566m  14m S  0.0  7.5   0:01.00 java                                                        
 4437 root      20   0 4495m 566m  14m S  0.0  7.5   2:10.19 java                                                        
 4438 root      20   0 4495m 566m  14m S  0.0  7.5   0:00.08 java                                                        
 4439 root      20   0 4495m 566m  14m S  0.0  7.5   0:00.07 java                                                        
 4440 root      20   0 4495m 566m  14m S  0.0  7.5   0:00.00 java                                                        
 4441 root      20   0 4495m 566m  14m S  0.0  7.5   0:06.90 java                                                        
 4446 root      20   0 4495m 566m  14m S  0.0  7.5   1:10.37 java                                                        
 4447 root      20   0 4495m 566m  14m S  0.0  7.5   0:04.77 java                                                        
 4448 root      20   0 4495m 566m  14m S  0.0  7.5   0:56.77 java

步骤三:转换线程ID

printf "%x\n" 4434  //转换成16进制

输出结果:

1152   //16进制

步骤四:定位cpu占用线程

输入命令:

$ jstack 4433 | grep 1152 -A 30

说明:

  • 4433:进程ID;
  • 1152:线程16进制ID;

输出结果:

"main" #1 prio=5 os_prio=0 tid=0x00007f3b5c00b800 nid=0x1152 runnable [0x00007f3b61c8d000]
   java.lang.Thread.State: RUNNABLE
	at java.net.PlainSocketImpl.socketAccept(Native Method)
	at java.net.AbstractPlainSocketImpl.accept(AbstractPlainSocketImpl.java:409)
	at java.net.ServerSocket.implAccept(ServerSocket.java:545)
	at java.net.ServerSocket.accept(ServerSocket.java:513)
	at org.apache.catalina.core.StandardServer.await(StandardServer.java:470)
	at org.apache.catalina.startup.Catalina.await(Catalina.java:793)
	at org.apache.catalina.startup.Catalina.start(Catalina.java:739)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:294)
	at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:428)

"VM Thread" os_prio=0 tid=0x00007f3b5c0fc000 nid=0x1155 runnable 

"GC task thread#0 (ParallelGC)" os_prio=0 tid=0x00007f3b5c020800 nid=0x1153 runnable 

"GC task thread#1 (ParallelGC)" os_prio=0 tid=0x00007f3b5c022800 nid=0x1154 runnable 

"VM Periodic Task Thread" os_prio=0 tid=0x00007f3b5cad6000 nid=0x117d waiting on condition 

JNI global references: 262
  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
jstack生成的Thread Dump日志.docx 系统线程状态 (Native Thread Status) 系统线程有如下状态: deadlock 死锁线程,一般指多个线程调用期间进入了相互资源占用,导致一直等待无法释放的情况。 runnable 一般指该线程正在执行状态中,该线程占用了资源,正在处理某个操作,如通过SQL语句查询数据库、对某个文件进行写入等。 blocked 线程正处于阻塞状态,指当前线程执行过程中,所需要的资源长时间等待却一直未能获取到,被容器的线程管理器标识为阻塞状态,可以理解为等待资源超时的线程。 waiting on condition 线程正处于等待资源或等待某个条件的发生,具体的原因需要结合下面堆栈信息进行分析。 (1)如果堆栈信息明确是应用代码,则证明该线程正在等待资源,一般是大量读取某种资源且该资源采用了资源锁的情况下,线程进入等待状态,等待资源的读取,或者正在等待其他线程的执行等。 (2)如果发现有大量的线程都正处于这种状态,并且堆栈信息中得知正等待网络读写,这是因为网络阻塞导致线程无法执行,很有可能是一个网络瓶颈的征兆: 网络非常繁忙,几乎消耗了所有的带宽,仍然有大量数据等待网络读写; 网络可能是空闲的,但由于路由或防火墙等原因,导致包无法正常到达; 所以一定要结合系统的一些性能观察工具进行综合分析,比如netstat统计单位时间的发送包的数量,看是否很明显超过了所在网络带宽的限制;观察CPU的利用率,看系统态的CPU时间是否明显大于用户态的CPU时间。这些都指向由于网络带宽所限导致的网络瓶颈。 (3)还有一种常见的情况是该线程在 sleep,等待 sleep 的时间到了,将被唤醒。 waiting for monitor entry 或 in Object.wait() Moniter 是Java中用以实现线程之间的互斥与协作的主要手段,它可以看成是对象或者class的锁,每个对象都有,也仅有一个 Monitor。 从上图可以看出,每个Monitor在某个时刻只能被一个线程拥有,该线程就是 "Active Thread",而其他线程都是 "Waiting Thread",分别在两个队列 "Entry Set"和"Waint Set"里面等待。其中在 "Entry Set" 中等待的线程状态是 waiting for monitor entry,在 "Wait Set" 中等待的线程状态是 in Object.wait()。 (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中发现这个情况,应该审视源码并对其进行改进。 (2)"Wait Set"里面的线程线程获得了Monitor,进入了临界区之后,如果发现线程继续运行的条件没有满足,它则调用对象(通常是被synchronized的对象)的wait()方法,放弃Monitor,进入 "Wait Set"队列。只有当别的线程在该对象上调用了 notify()或者notifyAll()方法,"Wait Set"队列中的线程才得到机会去竞争,但是只有一个线程获得对象的Monitor,恢复到运行态。"Wait Set"中的线程在Thread Dump中显示的状态为 in Object.wait()。通常来说, 通常来说,当CPU很忙的时候关注 Runnable 状态的线程,反之则关注 waiting for monitor entry 状态的线程。 JVM线程运行状态 (JVM Thread Status)

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值