场景:Java程序在运行的过程中出现了死锁或者运行的很慢,查看日志也没发现什么Exception,该如何解决呢?
-
一段死锁程序:
public class DeadLock { public static Object lockA = new Object(); public static Object lockB = new Object(); public static void main(String[] args) { new ThreadA().start(); new ThreadB().start(); } } class ThreadA extends Thread { @Override public void run() { synchronized(DeadLock.lockA) { System.out.println(Thread.currentThread().getName() + " get LockA"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } synchronized(DeadLock.lockB) { System.out.println(Thread.currentThread().getName() + " get LockB"); } } } } class ThreadB extends Thread { @Override public void run() { synchronized(DeadLock.lockB) { System.out.println(Thread.currentThread().getName() + " get LockB"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } synchronized(DeadLock.lockA) { System.out.println(Thread.currentThread().getName() + " get LockA"); } } } }
-
运行该程序会出现死锁:
-
使用JDK提供的一个非常强大的性能诊断工具:Thread Dump来解决。
3.1. 在Linux系统上通过执行
kill -3 PID
来获取某个java进程的Thread Dump信息。
3.2. 使用JDK自带的工具:jps 来获取执行中的java进程的PID。
3.3. 新开一个命令行窗口,执行jps获取运行中的java进程的PID。
3.4. 紧接着执行kill -3 1529
命令,我们就会发现在原来发生死锁的那个命令行窗口中出现了如下信息(Thread Dump信息):
3.5. 详细的信息如下:2018-11-10 11:55:08 Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.144-b01 mixed mode): "DestroyJavaVM" #10 prio=5 os_prio=0 tid=0x00007f4a74008800 nid=0x5fa waiting on condition [0x0000000000000000] java.lang.Thread.State: RUNNABLE "Thread-1" #9 prio=5 os_prio=0 tid=0x00007f4a740ca800 nid=0x604 waiting for monitor entry [0x00007f4a78808000] java.lang.Thread.State: BLOCKED (on object monitor) at ThreadB.run(DeadLock.java:43) - waiting to lock <0x00000000e0e5ddc8> (a java.lang.Object) - locked <0x00000000e0e5ddd8> (a java.lang.Object) "Thread-0" #8 prio=5 os_prio=0 tid=0x00007f4a740c8800 nid=0x603 waiting for monitor entry [0x00007f4a78909000] java.lang.Thread.State: BLOCKED (on object monitor) at ThreadA.run(DeadLock.java:25) - waiting to lock <0x00000000e0e5ddd8> (a java.lang.Object) - locked <0x00000000e0e5ddc8> (a java.lang.Object) "Service Thread" #7 daemon prio=9 os_prio=0 tid=0x00007f4a740b3000 nid=0x601 runnable [0x0000000000000000] java.lang.Thread.State: RUNNABLE "C1 CompilerThread1" #6 daemon prio=9 os_prio=0 tid=0x00007f4a740b0000 nid=0x600 waiting on condition [0x0000000000000000] java.lang.Thread.State: RUNNABLE "C2 CompilerThread0" #5 daemon prio=9 os_prio=0 tid=0x00007f4a740ae000 nid=0x5ff waiting on condition [0x0000000000000000] java.lang.Thread.State: RUNNABLE "Signal Dispatcher" #4 daemon prio=9 os_prio=0 tid=0x00007f4a740ac800 nid=0x5fe waiting on condition [0x0000000000000000] java.lang.Thread.State: RUNNABLE "Finalizer" #3 daemon prio=8 os_prio=0 tid=0x00007f4a74079800 nid=0x5fd in Object.wait() [0x00007f4a78f0f000] java.lang.Thread.State: WAITING (on object monitor) at java.lang.Object.wait(Native Method) - waiting on <0x00000000e0e08ec8> (a java.lang.ref.ReferenceQueue$Lock) at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:143) - locked <0x00000000e0e08ec8> (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) "Reference Handler" #2 daemon prio=10 os_prio=0 tid=0x00007f4a74074800 nid=0x5fc in Object.wait() [0x00007f4a79010000] java.lang.Thread.State: WAITING (on object monitor) at java.lang.Object.wait(Native Method) - waiting on <0x00000000e0e06b68> (a java.lang.ref.Reference$Lock) at java.lang.Object.wait(Object.java:502) at java.lang.ref.Reference.tryHandlePending(Reference.java:191) - locked <0x00000000e0e06b68> (a java.lang.ref.Reference$Lock) at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:153) "VM Thread" os_prio=0 tid=0x00007f4a7406d000 nid=0x5fb runnable "VM Periodic Task Thread" os_prio=0 tid=0x00007f4a740b6800 nid=0x602 waiting on condition JNI global references: 6 Found one Java-level deadlock: ============================= "Thread-1": waiting to lock monitor 0x00007f4a580062c8 (object 0x00000000e0e5ddc8, a java.lang.Object), which is held by "Thread-0" "Thread-0": waiting to lock monitor 0x00007f4a58004e28 (object 0x00000000e0e5ddd8, a java.lang.Object), which is held by "Thread-1" Java stack information for the threads listed above: =================================================== "Thread-1": at ThreadB.run(DeadLock.java:43) - waiting to lock <0x00000000e0e5ddc8> (a java.lang.Object) - locked <0x00000000e0e5ddd8> (a java.lang.Object) "Thread-0": at ThreadA.run(DeadLock.java:25) - waiting to lock <0x00000000e0e5ddd8> (a java.lang.Object) - locked <0x00000000e0e5ddc8> (a java.lang.Object) Found 1 deadlock. Heap def new generation total 9792K, used 1393K [0x00000000e0e00000, 0x00000000e18a0000, 0x00000000eb400000) eden space 8704K, 16% used [0x00000000e0e00000, 0x00000000e0f5c560, 0x00000000e1680000) from space 1088K, 0% used [0x00000000e1680000, 0x00000000e1680000, 0x00000000e1790000) to space 1088K, 0% used [0x00000000e1790000, 0x00000000e1790000, 0x00000000e18a0000) tenured generation total 21888K, used 0K [0x00000000eb400000, 0x00000000ec960000, 0x0000000100000000) the space 21888K, 0% used [0x00000000eb400000, 0x00000000eb400000, 0x00000000eb400200, 0x00000000ec960000) Metaspace used 2485K, capacity 4490K, committed 4864K, reserved 1056768K class space used 269K, capacity 386K, committed 512K, reserved 1048576K
可以看到这里发现了一个死锁:
“Thread-1”:
at ThreadB.run(DeadLock.java:43)
- waiting to lock <0x00000000e0e5ddc8> (a java.lang.Object)
- locked <0x00000000e0e5ddd8> (a java.lang.Object)
“Thread-0”:
at ThreadA.run(DeadLock.java:25)
- waiting to lock <0x00000000e0e5ddd8> (a java.lang.Object)
- locked <0x00000000e0e5ddc8> (a java.lang.Object)Found 1 deadlock.
(1). Thread-1在等待锁住<0x00000000e0e5ddc8>,但是Thread-0已经锁住了<0x00000000e0e5ddc8>。
(2). 分别发生在DeadLock.java的43行和25行,定位到代码对应的位置:13 class ThreadA extends Thread { 14 15 @Override 16 public void run() { 17 synchronized(DeadLock.lockA) { 18 System.out.println(Thread.currentThread().getName() + " get LockA"); 19 try { 20 Thread.sleep(1000); 21 } catch (InterruptedException e) { 22 e.printStackTrace(); 23 } 24 synchronized(DeadLock.lockB) { 25 System.out.println(Thread.currentThread().getName() + " get LockB"); 26 } 27 } 28 } 29 }
31 class ThreadB extends Thread { 32 33 @Override 34 public void run() { 35 synchronized(DeadLock.lockB) { 36 System.out.println(Thread.currentThread().getName() + " get LockB"); 37 try { 38 Thread.sleep(1000); 39 } catch (InterruptedException e) { 40 e.printStackTrace(); 41 } 42 synchronized(DeadLock.lockA) { 43 System.out.println(Thread.currentThread().getName() + " get LockA"); 44 } 45 } 46 } 47 }
发现两个线程分别在持有了各自的锁的前提下去抢夺对方的锁,结果陷入死锁,使用
kill -9 1529
杀掉死锁进程,修改代码,重新部署到服务器,问题解决。 -
另外,正常运行的java线程的状态是RUNNABLE,陷入阻塞或者有问题的线程将处于BLOCKED状态,根据Threa Dump信息也可以看出来。