"threadB" #10 prio=5 os_prio=0 tid=0x00007f05bc0f0000 nid=0x50f1 waiting for monitor entry [0x00007f05a589d000] java.lang.Thread.State: BLOCKED (on object monitor) at Main$2.run(Main.java:32) - waiting to lock <0x000000078665b048> (a java.lang.Object) - locked <0x000000078665b058> (a java.lang.Object) at java.lang.Thread.run(Thread.java:748)
"threadA" #9 prio=5 os_prio=0 tid=0x00007f05bc0ee000 nid=0x50f0 waiting for monitor entry [0x00007f05a599e000] java.lang.Thread.State: BLOCKED (on object monitor) at Main$1.run(Main.java:18) - waiting to lock <0x000000078665b058> (a java.lang.Object) - locked <0x000000078665b048> (a java.lang.Object) at java.lang.Thread.run(Thread.java:748)
"Finalizer" #3 daemon prio=8 os_prio=0 tid=0x00007f05bc084000 nid=0x50e8 in Object.wait() [0x00007f05a6e83000] java.lang.Thread.State: WAITING (on object monitor) at java.lang.Object.wait(Native Method) - waiting on <0x0000000786608ed0> (a java.lang.ref.ReferenceQueue$Lock) at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:144) - locked <0x0000000786608ed0> (a java.lang.ref.ReferenceQueue$Lock) at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:165) at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:216)
"Reference Handler" #2 daemon prio=10 os_prio=0 tid=0x00007f05bc081800 nid=0x50e7 in Object.wait() [0x00007f05a6f84000] java.lang.Thread.State: WAITING (on object monitor) at java.lang.Object.wait(Native Method) - waiting on <0x0000000786606bf8> (a java.lang.ref.Reference$Lock) at java.lang.Object.wait(Object.java:502) at java.lang.ref.Reference.tryHandlePending(Reference.java:191) - locked <0x0000000786606bf8> (a java.lang.ref.Reference$Lock) at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:153)
"VM Periodic Task Thread" os_prio=0 tid=0x00007f05bc0dd000 nid=0x50ee waiting on condition
JNI global references: 5
Found one Java-level deadlock: ============================= "threadB": waiting to lock monitor 0x00007f058c002418 (object 0x000000078665b048, a java.lang.Object), which is held by "threadA" "threadA": waiting to lock monitor 0x00007f058c0064b8 (object 0x000000078665b058, a java.lang.Object), which is held by "threadB"
Java stack information for the threads listed above: =================================================== "threadB": at Main$2.run(Main.java:32) - waiting to lock <0x000000078665b048> (a java.lang.Object) - locked <0x000000078665b058> (a java.lang.Object) at java.lang.Thread.run(Thread.java:748) "threadA": at Main$1.run(Main.java:18) - waiting to lock <0x000000078665b058> (a java.lang.Object) - locked <0x000000078665b048> (a java.lang.Object) at java.lang.Thread.run(Thread.java:748)
java.lang.Thread.State: RUNNABLE at java.io.FileInputStream.readBytes(Native Method) at java.io.FileInputStream.read(FileInputStream.java:255) at java.io.BufferedInputStream.fill(BufferedInputStream.java:246) at java.io.BufferedInputStream.read(BufferedInputStream.java:265) - locked <0x000000078661b698> (a java.io.BufferedInputStream) at Main.main(Main.java:10)
处于RUNNING或者READY情形的线程:
1 2
java.lang.Thread.State: RUNNABLE at Main.main(Main.java:9)
java.lang.Thread.State: BLOCKED (on object monitor) at Main$1.run(Main.java:18) - waiting to lock <0x000000078665b058> (a java.lang.Object) - locked <0x000000078665b048> (a java.lang.Object) at java.lang.Thread.run(Thread.java:748)
java.lang.Thread.State: WAITING (on object monitor) at java.lang.Object.wait(Native Method) - waiting on <0x000000078665adc8> (a java.lang.Object) at java.lang.Object.wait(Object.java:502) at Main.main(Main.java:11) - locked <0x000000078665adc8> (a java.lang.Object)
调用LockSupport类的park()方法的线程:
1 2 3 4
java.lang.Thread.State: WAITING (parking) at sun.misc.Unsafe.park(Native Method) at java.util.concurrent.locks.LockSupport.park(LockSupport.java:304) at Main.main(Main.java:7)
调用LockSupport类的park(Object blocker)方法的线程:
1 2 3 4 5
java.lang.Thread.State: WAITING (parking) at sun.misc.Unsafe.park(Native Method) - parking to wait for <0x000000078665ad88> (a java.lang.Object) at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175) at Main.main(Main.java:7)
在《Java并发编程基础》中我们知道,LockSupport类的方法park()和相应的重载方法park(Object blocker)核心语义一致,他们的差别也仅在于:在jstack命令打印结果中,包含后者的执行路径栈与包含前者的执行路径栈相比,额外多了一句形如- parking to wait for <0x000000078665ad88> (a java.lang.Object)的描述
需要对调用LockSupport类park(Object blocker)方法时的形如- parking to wait for <0x000000078665ad88> (a java.lang.Object)描述与申请synchronized锁时的形如- waiting to lock <0x00000007ab3f31b8> (a java.lang.Object)描述作区分:后者中的0x00000007ab3f31b8指代一个synchronized锁对象,线程因申请该synchronized锁对象不得而挂起,因此描述具有具体明确的语法语义;前者中的0x000000078665ad88指代传入的blocker对象,该blocker对象与线程挂起不一定有关系,因此描述不具有具体明确的语法语义,只是起到打印上下文信息的日志作用
4、TIMED_WAITING 调用Thread类sleep(long millis)/sleep(long millis, int nanos)方法的线程:
1 2 3
java.lang.Thread.State: TIMED_WAITING (sleeping) at java.lang.Thread.sleep(Native Method) at Main.main(Main.java:8)
调用Object类wait(long timeout)/wait(long timeout, int nanos)方法的线程:
1 2 3 4 5
java.lang.Thread.State: TIMED_WAITING (on object monitor) at java.lang.Object.wait(Native Method) - waiting on <0x000000078665ad70> (a java.lang.Object) at Main.main(Main.java:6) - locked <0x000000078665ad70> (a java.lang.Object)
java.lang.Thread.State: TIMED_WAITING (parking) at sun.misc.Unsafe.park(Native Method) at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:338) at Main.main(Main.java:5)
调用LockSupport类parkNanos(Object blocker, long nanos)/parkUntil(Object blocker, long deadline)方法的线程:
1 2 3 4 5
java.lang.Thread.State: TIMED_WAITING (parking) at sun.misc.Unsafe.park(Native Method) - parking to wait for <0x000000078665ad28> (a java.lang.Object) at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:215) at Main.main(Main.java:6)
备注:
对以上最后一个例子中形如- parking to wait for <0x000000078665ad28> (a java.lang.Object)描述的说明参见上一小节的备注
1.2、线程栈信息其他
1.2.1、头部
比如“线程栈信息示例1”中的:
1 2
2021-01-12 21:50:42 Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.211-b12 mixed mode):
Found one Java-level deadlock: ============================= "threadB": waiting to lock monitor 0x00007f058c002418 (object 0x000000078665b048, a java.lang.Object), which is held by "threadA" "threadA": waiting to lock monitor 0x00007f058c0064b8 (object 0x000000078665b058, a java.lang.Object), which is held by "threadB"
Java stack information for the threads listed above: =================================================== "threadB": at Main$2.run(Main.java:32) - waiting to lock <0x000000078665b048> (a java.lang.Object) - locked <0x000000078665b058> (a java.lang.Object) at java.lang.Thread.run(Thread.java:748) "threadA": at Main$1.run(Main.java:18) - waiting to lock <0x000000078665b058> (a java.lang.Object) - locked <0x000000078665b048> (a java.lang.Object) at java.lang.Thread.run(Thread.java:748)
Found 1 deadlock.
需要注意的是,上述描述“发现死锁”的部分内容(从Found one Java-level deadlock:开始到Found 1 deadlock.为止)只在探测到存在该种简单死锁情形时才会出现。
能够快速方便定位被最多线程等待的synchronized锁(在“Monitors”页面中会标红被怀疑的synchronized锁),紧接着也能快速方便找到持有该synchronized锁的线程。 不过对于该工具,笔者感觉有两个小瑕疵:1)“State”列采用了“基本描述”字段值,而没有采用来自“详细描述”字段中第一行的精确的线程状态值;2)将形如- parking to wait for <0x000000078665ad88> (a java.lang.Object)描述中的Park锁锁标记与synchronized锁锁标记混淆