线程转储是一个JVM活动线程的列表,它对于分析系统瓶颈和死锁非常有用。
首先介绍一下jdk自带的三个小工具
jdk自带工具
jps | 显示指定系统内所有的HotSpot虚拟机线程 |
jmap | 生成虚拟机的内存转储快照 |
jstack | 显示虚拟机的线程快照 |
现在实验一个简单死锁程序,程序示例可以直接查看Java很简单的死锁例子。那么如何生成内存转储快照或者如何显示线程快照呢?步骤如下
- 进入到当前程序运行的jdk的bin目录下,也就是这三个工具的所在目录。
- 命令行输入jps,查出当前虚拟机的所有线程的pid。
- 输入jmap -dump:format=b,<filename> <pid> 生成dump快照,其中format=b表示以二进制文件生成。<filename>表示文件名称 <pid>表示要生成那个线程的快照文件。这一步不是必须的。
- 输入jstack <pid>,就可以得到线程快照信息。
下面就从上面所提到的死锁案例进行分析:
第一步,第二步其中APPMain就是运行程序的主线程
C:\Users\Administrator>cd C:\Program Files\Java\jdk1.8.0_181\bin
C:\Program Files\Java\jdk1.8.0_181\bin>jps
7696
8288 Launcher
9572 Jps
2588 AppMain
第三步,在G文件夹下生成了a.dump的快照文件,如果需要对生成的文件进行查看,可以使用jdk自带工具VisualVM,或者更专业的dump文件分析工具Eclipse Memory Analuzer等。
C:\Program Files\Java\jdk1.8.0_181\bin>jmap -dump:format=b,file=G:/a.dump 2588
Dumping heap to G:\a.dump ...
Heap dump file created
第四步,生成进程快照信息,中间省略了一部分信息
C:\Program Files\Java\jdk1.8.0_181\bin>jstack 2588
2019-05-07 22:50:05
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.181-b13 mixed mode):
省略...
Found one Java-level deadlock:
=============================
"线程2":
waiting to lock monitor 0x0000000056cabd08 (object 0x00000000dbb91cb8, a java.
lang.Object),
which is held by "线程1"
"线程1":
waiting to lock monitor 0x0000000056caa868 (object 0x00000000dbb91cc8, a java.
lang.Object),
which is held by "线程2"
Java stack information for the threads listed above:
===================================================
"线程2":
at test.LockTest$2.run(LockTest.java:41)
- waiting to lock <0x00000000dbb91cb8> (a java.lang.Object)
- locked <0x00000000dbb91cc8> (a java.lang.Object)
at java.lang.Thread.run(Thread.java:748)
"线程1":
at test.LockTest$1.run(LockTest.java:24)
- waiting to lock <0x00000000dbb91cc8> (a java.lang.Object)
- locked <0x00000000dbb91cb8> (a java.lang.Object)
at java.lang.Thread.run(Thread.java:748)
Found 1 deadlock.
结果分析:
可以看出线程1和线程2死锁在对对象a锁的获取上。这里我不是很理解为什么线程1和线程2都是阻塞在a对象的获取上,两个线程waiting to lock,locked的地址是岔开的,也就是我理解的线程1持有对象a在等待b对象,线程2持有对象b在等待a对象,但是为什么括号里写的都是a对象,这个我不是很理解。
在Thread类中,有api也可以获得线程堆栈状态
Thread.currentThread().getStackTrace()可以获得当前线程的堆栈状态。
参考文献
[1]深入理解Java虚拟机