简介: 如果咱们在程序中遇到线程死锁的时候,该怎么去解决呢? 本文将会从一个理论的例子登程,一步一步的揭开java问题解决的面纱。
简介
如果咱们在程序中遇到线程死锁的时候,该怎么去解决呢?
本文将会从一个理论的例子登程,一步一步的揭开java问题解决的面纱。
死锁的代码
写过java多线程程序的人应该都晓得,多线程中一个很重要的事件就是状态的同步,然而在状态同步的过程中,一不小心就有可能会导致死锁的问题。
一个最简略的死锁状况就是thread1占有资源1,而后又要去获取资源2. 而thread2占有资源2,又要去获取资源1的状况。
举个具体的例子:
public class TestDeadLock { public static Object lock1= new Object(); public static Object lock2= new Object(); public static void main(String[] args) { Runnable runnable1= ()-> { System.out.println("in lock1"); synchronized(lock1){ System.out.println("Lock1 lock obj1"); try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } synchronized(lock2){ System.out.println("Lock1 lock obj2"); } } }; Runnable runnable2= ()-> { System.out.println("in lock2"); synchronized(lock2){ System.out.println("Lock2 lock obj2"); try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } synchronized(lock1){ System.out.println("Lock2 lock obj1"); } } }; Thread a = new Thread(runnable1); Thread b = new Thread(runnable2); a.start(); b.start(); }}
咱们运行下面的代码:
in lock1Lock1 lock obj1in lock2Lock2 lock obj2
发送了锁循环期待的状况,程序执行不上来了,发送了死锁。
control+break命令
在代码很简略的状况下,咱们很容易就能剖析进去死锁的起因,然而如果是在一个十分宏大的线上我的项目的时候,剖析代码就没有那么容易了。
怎么做呢?
明天教给大家一个办法,应用control+break命令。
control+break在linux示意的是Control+backslash,而在Windows上面就是Control+Break按钮。
当然,还有一个更加通用的就是应用:
kill -QUIT pid命令。
咱们用jps命令获取到执行java程序的过程id,而后执行kill -QUIT命令。
执行结束,咱们会发现运行的java过程会输入一些额定的日志,这些额定的日志就是咱们找出死锁的关键因素。
留神,这个kill命令并不会终止程序的运行。
输入的内容比拟多,咱们一部分一部分的解说。
Full thread dump
日志的第一局部就是Full thread dump,蕴含了JVM中的所有线程的状态信息。
咱们看一下咱们代码中的两个要害线程信息:
"Thread-0" #13 prio=5 os_prio=31 cpu=4.86ms elapsed=230.16s tid=0x00007fc926061800 nid=0x6403 waiting for monitor entry [0x0000700008d6a000] java.lang.Thread.State: BLOCKED (on object monitor) at com.flydean.TestDeadLock.lambda$main$0(TestDeadLock.java:21) - waiting to lock <0x0000000787e868f0> (a java.lang.Object) - locked <0x0000000787e868e0> (a java.lang.Object) at com.flydean.TestDeadLock$$Lambda$14/0x0000000800b69840.run(Unknown Source) at java.lang.Thread.run(java.base@14.0.1/Thread.java:832)"Thread-1" #14 prio=5 os_prio=31 cpu=4.32ms elapsed=230.16s tid=0x00007fc924869800 nid=0x6603 waiting for monitor entry [0x0000700008e6d000] java.lang.Thread.State: BLOCKED (on object monitor) at com.flydean.TestDeadLock.lambda$main$1(TestDeadLock.java:36) - waiting to lock <0x0000000787e868e0> (a java.lang.Object) - locked <0x0000000787e868f0> (a java.lang.Object) at com.flydean.TestDeadLock$$Lambda$15/0x0000000800b69c40.run(Unknown Source) at java.lang.Thread.run(java.base@14.0.1/Thread.java:832)
下面的输入列出了线程名字,线程的优先级,cpu工夫,是否是daemon线程,线程ID,线程状态等有用的信息。
看到下面的输入,咱们看到两个线程都是处于BLOCKED状态,都在期待object monitor。
还记得线程的几个状态吗? 咱们再来温习一下。
死锁检测
接下来的局部就是咱们最关怀的死锁检测了。
Found one Java-level deadlock:============================="Thread-0": waiting to lock monitor 0x00007fc926807e00 (object 0x0000000787e868f0, a java.lang.Object), which is held by "Thread-1""Thread-1": waiting to lock monitor 0x00007fc926807f00 (object 0x0000000787e868e0, a java.lang.Object), which is held by "Thread-0"Java stack information for the threads listed above:==================================================="Thread-0": at com.flydean.TestDeadLock.lambda$main$0(TestDeadLock.java:21) - waiting to lock <0x0000000787e868f0> (a java.lang.Object) - locked <0x0000000787e868e0> (a java.lang.Object) at com.flydean.TestDeadLock$$Lambda$14/0x0000000800b69840.run(Unknown Source) at java.lang.Thread.run(java.base@14.0.1/Thread.java:832)"Thread-1": at com.flydean.TestDeadLock.lambda$main$1(TestDeadLock.java:36) - waiting to lock <0x0000000787e868e0> (a java.lang.Object) - locked <0x0000000787e868f0> (a java.lang.Object) at com.flydean.TestDeadLock$$Lambda$15/0x0000000800b69c40.run(Unknown Source) at java.lang.Thread.run(java.base@14.0.1/Thread.java:832)Found 1 deadlock.
下面的日志咱们能够很显著的看进去,两个线程别离取得了对方须要的锁,所以导致了死锁。
同时还具体的列出了thread stack的信息,供咱们剖析。
如果咱们增加了参数-XX:+PrintConcurrentLocks,还会输入各个线程的取得的concurrent lock信息。
Heap信息
最初一部分是Heap的统计信息:
Heap garbage-first heap total 133120K, used 3888K [0x0000000780000000, 0x0000000800000000) region size 1024K, 4 young (4096K), 0 survivors (0K) Metaspace used 1122K, capacity 4569K, committed 4864K, reserved 1056768K class space used 108K, capacity 412K, committed 512K, reserved 1048576K
如果咱们增加了-XX:+PrintClassHistogram命令,还能够额定的输入class直方图统计信息。
总结
下面就是应用Control+Break命令来剖析java死锁问题的具体例子,心愿大家可能喜爱。
本文作者:flydean程序那些事本文链接:http://www.flydean.com/jvm-diagnostic-control-break/
本文起源:flydean的博客
欢送关注我的公众号:程序那些事,更多精彩等着您!