[Java]一個DeadLock(死鎖)的例子

weixin_33912445發表於2017-12-09

今天在InteliJ裡跑了一下,模擬了一個死鎖。
synchronized關鍵字修飾的方法可能會導致死鎖。(Synchronized只能修飾方法,就像volatile只能修飾變數)。
先簡單介紹一下,下面這個死鎖產生的原因,是A執行緒需要依次獲取lock1和lock2才能分別列印一句話,B執行緒需要依次獲取lock2和lock1才能分別列印一句話,那兩個執行緒非同步執行的時候,有兩種情況:
情形1:
A迅速地依次持有lock1,持有lock2,釋放lock2,釋放lock1,順利地列印了兩句話。
然後B持有lock2,持有lock1,釋放lock1,釋放lock2,也順利地列印了兩句話。
情形2:
A持有了lock1,列印了第一句話(沒有釋放lock1),此時B持有了lock2,列印了第一句話;接著A想持有lock2了,就等著B釋放lock2,但是lock2是釋放不掉的,因為lock2要想釋放,就必須先獲取lock1並執行任務。

注意,兩把鎖一定要巢狀呼叫。

看程式碼比較容易理解:

public class TestDeadLock {
    
    public void run() {
        MyThread mt = new MyThread();
        new Thread(mt, "張三").start();
        new Thread(mt, "李四").start();
    }
    
    class MyThread implements Runnable {
        //lock要寫成final的,否則如果lock指向變了,鎖就失效了
        private final Object mLock1 = new Object();
        private final Object mLock2 = new Object();
        //boolean用來確保兩個執行緒獲得不同的鎖。
        private boolean flag = true;
        

        @Override
        public void run() {
            if (flag) {
                flag = false;
                //注意,兩把鎖一要巢狀呼叫
                synchronized (mLock1) {
                    System.out.println(Thread.currentThread().getName() + " have mLock1");
//                  try {
//                      Thread.sleep(100);
//                  } catch (InterruptedException e) {
//                      e.printStackTrace();
//                  }
                    synchronized (mLock2) {
                        System.out.println(Thread.currentThread().getName() + " have mLock2");
                    }
                }
            } else {
                flag = true;
                synchronized (mLock2) {
                    System.out.println(Thread.currentThread().getName() + " have mLock2");
//                  try {
//                      Thread.sleep(100);
//                  } catch (InterruptedException e) {
//                      e.printStackTrace();
//                  }
                    synchronized (mLock1) {
                        System.out.println(Thread.currentThread().getName() + " have mLock1");
                    }
                }
            }
        }
    }
    
    public static void main(String[] args) {
        new TestDeadLock().run();
    }
}

我把sleep的部分去掉了,這樣由於執行緒搶佔CPU資源,每次執行的結果會不同(上面提到的兩種情形)。
下面的截圖對應第一種情形:


3326381-b41ed889a805e85a.png
image.png

下面的截圖對應第二種情形,一直卡在這兒了,死鎖出現了:

3326381-2b44962b30ce3b12.png
image.png

那如果放開sleep的註釋,就會必現第二種情形了。

Ref:
http://blog.csdn.net/u011345136/article/details/45770835
http://blog.csdn.net/qinjienj/article/details/7578582

相關文章