首页 > 技术文章 > 线程死锁

agilestyle 2019-08-28 16:03 原文

原创转载请注明出处:https://www.cnblogs.com/agilestyle/p/11424647.html

 

死锁:一组互相竞争资源的线程因互相等待,导致“永久”阻塞的现象。 

解决死锁,要么重启,要么规避

那如何避免死锁呢?要避免死锁就需要分析死锁发生的条件,只有以下这四个条件都发生时才会出现死锁:

  1. 互斥,共享资源 X 和 Y 只能被一个线程占用;
  2. 占有且等待,线程 T1 已经取得共享资源 X,在等待共享资源 Y 的时候,不释放共享资源 X;
  3. 不可抢占,其他线程不能强行抢占线程 T1 占有的资源;
  4. 循环等待,线程 T1 等待线程 T2 占有的资源,线程 T2 等待线程 T1 占有的资源,就是循环等待。

 

反过来分析,也就是说只要破坏其中一个,就可以成功避免死锁的发生。 

 

模拟一个死锁的程序

 1 package org.fool.test;
 2 
 3 import java.util.concurrent.TimeUnit;
 4 import java.util.concurrent.locks.Lock;
 5 import java.util.concurrent.locks.ReentrantLock;
 6 
 7 public class DeadLockTest {
 8     private static Lock lockA = new ReentrantLock();
 9     private static Lock lockB = new ReentrantLock();
10 
11     public static void main(String[] args) {
12         new Thread(new Runnable() {
13             @Override
14             public void run() {
15                 try {
16                     lockA.lock();
17                     System.out.println("=====Thread A outer invoked...=====");
18                     TimeUnit.SECONDS.sleep(3);
19                     try {
20                         lockB.lock();
21                         System.out.println("=====Thread A inner invoked...=====");
22                     } finally {
23                         lockB.unlock();
24                     }
25                 } catch (InterruptedException e) {
26                     e.printStackTrace();
27                 } finally {
28                     lockA.unlock();
29                 }
30             }
31         }, "Thread-A").start();
32 
33         new Thread(new Runnable() {
34             @Override
35             public void run() {
36                 try {
37                     lockB.lock();
38                     System.out.println("=====Thread B outer invoked...=====");
39                     TimeUnit.SECONDS.sleep(3);
40                     try {
41                         lockA.lock();
42                         System.out.println("=====Thread B inner invoked...=====");
43                     } finally {
44                         lockA.unlock();
45                     }
46                 } catch (InterruptedException e) {
47                     e.printStackTrace();
48                 } finally {
49                     lockB.unlock();
50                 }
51             }
52         }, "Thread-B").start();
53     }
54 
55 }

打包成可执行jar包后,运行java -jar hello-deadlock-1.0-SNAPSHOT.jar

 

ps -ef | grep java 找出对应的pid,使用jstack打出堆栈信息

  1 2019-04-25 15:49:30  
  2 Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.121-b13 mixed mode):  
  3   
  4 "Attach Listener" #13 daemon prio=9 os_prio=31 tid=0x00007fb881058800 nid=0x1407 waiting on condition [0x0000000000000000]  
  5    java.lang.Thread.State: RUNNABLE  
  6   
  7 "DestroyJavaVM" #12 prio=5 os_prio=31 tid=0x00007fb882802000 nid=0x1c03 waiting on condition [0x0000000000000000]  
  8    java.lang.Thread.State: RUNNABLE  
  9   
 10 "Thread-B" #11 prio=5 os_prio=31 tid=0x00007fb883807000 nid=0x5903 waiting on condition [0x0000700002f89000]  
 11    java.lang.Thread.State: WAITING (parking)  
 12     at sun.misc.Unsafe.park(Native Method)  
 13     - parking to wait for  <0x000000076abdaa00> (a java.util.concurrent.locks.ReentrantLock$NonfairSync)  
 14     at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)  
 15     at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:836)  
 16     at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(AbstractQueuedSynchronizer.java:870)  
 17     at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:1199)  
 18     at java.util.concurrent.locks.ReentrantLock$NonfairSync.lock(ReentrantLock.java:209)  
 19     at java.util.concurrent.locks.ReentrantLock.lock(ReentrantLock.java:285)  
 20     at org.fool.test.DeadLockTest$2.run(DeadLockTest.java:41)  
 21     at java.lang.Thread.run(Thread.java:745)  
 22   
 23 "Thread-A" #10 prio=5 os_prio=31 tid=0x00007fb8800a7800 nid=0x5703 waiting on condition [0x0000700002e86000]  
 24    java.lang.Thread.State: WAITING (parking)  
 25     at sun.misc.Unsafe.park(Native Method)  
 26     - parking to wait for  <0x000000076abdaa30> (a java.util.concurrent.locks.ReentrantLock$NonfairSync)  
 27     at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)  
 28     at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:836)  
 29     at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(AbstractQueuedSynchronizer.java:870)  
 30     at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:1199)  
 31     at java.util.concurrent.locks.ReentrantLock$NonfairSync.lock(ReentrantLock.java:209)  
 32     at java.util.concurrent.locks.ReentrantLock.lock(ReentrantLock.java:285)  
 33     at org.fool.test.DeadLockTest$1.run(DeadLockTest.java:20)  
 34     at java.lang.Thread.run(Thread.java:745)  
 35   
 36 "Service Thread" #9 daemon prio=9 os_prio=31 tid=0x00007fb882051000 nid=0x5303 runnable [0x0000000000000000]  
 37    java.lang.Thread.State: RUNNABLE  
 38   
 39 "C1 CompilerThread3" #8 daemon prio=9 os_prio=31 tid=0x00007fb880009800 nid=0x5103 waiting on condition [0x0000000000000000]  
 40    java.lang.Thread.State: RUNNABLE  
 41   
 42 "C2 CompilerThread2" #7 daemon prio=9 os_prio=31 tid=0x00007fb881044000 nid=0x4f03 waiting on condition [0x0000000000000000]  
 43    java.lang.Thread.State: RUNNABLE  
 44   
 45 "C2 CompilerThread1" #6 daemon prio=9 os_prio=31 tid=0x00007fb881043000 nid=0x4d03 waiting on condition [0x0000000000000000]  
 46    java.lang.Thread.State: RUNNABLE  
 47   
 48 "C2 CompilerThread0" #5 daemon prio=9 os_prio=31 tid=0x00007fb882025800 nid=0x4b03 waiting on condition [0x0000000000000000]  
 49    java.lang.Thread.State: RUNNABLE  
 50   
 51 "Signal Dispatcher" #4 daemon prio=9 os_prio=31 tid=0x00007fb88200c800 nid=0x4903 runnable [0x0000000000000000]  
 52    java.lang.Thread.State: RUNNABLE  
 53   
 54 "Finalizer" #3 daemon prio=8 os_prio=31 tid=0x00007fb880858000 nid=0x3903 in Object.wait() [0x000070000266e000]  
 55    java.lang.Thread.State: WAITING (on object monitor)  
 56     at java.lang.Object.wait(Native Method)  
 57     - waiting on <0x000000076ab08ec8> (a java.lang.ref.ReferenceQueue$Lock)  
 58     at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:143)  
 59     - locked <0x000000076ab08ec8> (a java.lang.ref.ReferenceQueue$Lock)  
 60     at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:164)  
 61     at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:209)  
 62   
 63 "Reference Handler" #2 daemon prio=10 os_prio=31 tid=0x00007fb880855800 nid=0x3703 in Object.wait() [0x000070000256b000]  
 64    java.lang.Thread.State: WAITING (on object monitor)  
 65     at java.lang.Object.wait(Native Method)  
 66     - waiting on <0x000000076ab06b68> (a java.lang.ref.Reference$Lock)  
 67     at java.lang.Object.wait(Object.java:502)  
 68     at java.lang.ref.Reference.tryHandlePending(Reference.java:191)  
 69     - locked <0x000000076ab06b68> (a java.lang.ref.Reference$Lock)  
 70     at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:153)  
 71   
 72 "VM Thread" os_prio=31 tid=0x00007fb881002800 nid=0x3503 runnable  
 73   
 74 "GC task thread#0 (ParallelGC)" os_prio=31 tid=0x00007fb880014800 nid=0x2503 runnable  
 75   
 76 "GC task thread#1 (ParallelGC)" os_prio=31 tid=0x00007fb880015800 nid=0x2703 runnable  
 77   
 78 "GC task thread#2 (ParallelGC)" os_prio=31 tid=0x00007fb880016000 nid=0x2903 runnable  
 79   
 80 "GC task thread#3 (ParallelGC)" os_prio=31 tid=0x00007fb880016800 nid=0x2b03 runnable  
 81   
 82 "GC task thread#4 (ParallelGC)" os_prio=31 tid=0x00007fb881001000 nid=0x2d03 runnable  
 83   
 84 "GC task thread#5 (ParallelGC)" os_prio=31 tid=0x00007fb881002000 nid=0x2f03 runnable  
 85   
 86 "GC task thread#6 (ParallelGC)" os_prio=31 tid=0x00007fb880800800 nid=0x3103 runnable  
 87   
 88 "GC task thread#7 (ParallelGC)" os_prio=31 tid=0x00007fb880801000 nid=0x3303 runnable  
 89   
 90 "VM Periodic Task Thread" os_prio=31 tid=0x00007fb880828800 nid=0x5503 waiting on condition  
 91   
 92 JNI global references: 6  
 93   
 94   
 95 Found one Java-level deadlock:  
 96 =============================  
 97 "Thread-B":  
 98   waiting for ownable synchronizer 0x000000076abdaa00, (a java.util.concurrent.locks.ReentrantLock$NonfairSync),  
 99   which is held by "Thread-A"  
100 "Thread-A":  
101   waiting for ownable synchronizer 0x000000076abdaa30, (a java.util.concurrent.locks.ReentrantLock$NonfairSync),  
102   which is held by "Thread-B"  
103   
104 Java stack information for the threads listed above:  
105 ===================================================  
106 "Thread-B":  
107     at sun.misc.Unsafe.park(Native Method)  
108     - parking to wait for  <0x000000076abdaa00> (a java.util.concurrent.locks.ReentrantLock$NonfairSync)  
109     at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)  
110     at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:836)  
111     at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(AbstractQueuedSynchronizer.java:870)  
112     at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:1199)  
113     at java.util.concurrent.locks.ReentrantLock$NonfairSync.lock(ReentrantLock.java:209)  
114     at java.util.concurrent.locks.ReentrantLock.lock(ReentrantLock.java:285)  
115     at org.fool.test.DeadLockTest$2.run(DeadLockTest.java:41)  
116     at java.lang.Thread.run(Thread.java:745)  
117 "Thread-A":  
118     at sun.misc.Unsafe.park(Native Method)  
119     - parking to wait for  <0x000000076abdaa30> (a java.util.concurrent.locks.ReentrantLock$NonfairSync)  
120     at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)  
121     at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:836)  
122     at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(AbstractQueuedSynchronizer.java:870)  
123     at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:1199)  
124     at java.util.concurrent.locks.ReentrantLock$NonfairSync.lock(ReentrantLock.java:209)  
125     at java.util.concurrent.locks.ReentrantLock.lock(ReentrantLock.java:285)  
126     at org.fool.test.DeadLockTest$1.run(DeadLockTest.java:20)  
127     at java.lang.Thread.run(Thread.java:745)  
128   
129 Found 1 deadlock.

Note:

tid: java线程ID 

nid: native线程ID

 

推荐阅读