2016-04-25 7 views
8

になぜ起こるか私はマルチスレッドに新しいですし、私はこの例に出くわしたの理解:デッドロックは、この実装

public class TestThread { 
    public static Object Lock1 = new Object(); 
    public static Object Lock2 = new Object(); 

    public static void main(String args[]) { 

     ThreadDemo1 T1 = new ThreadDemo1(); 
     ThreadDemo2 T2 = new ThreadDemo2(); 
     T1.start(); 
     T2.start(); 
    } 

    private static class ThreadDemo1 extends Thread { 
     public void run() { 
     synchronized (Lock1) { 
      System.out.println("Thread 1: Holding lock 1..."); 
      try { Thread.sleep(10); } 
      catch (InterruptedException e) {} 
      System.out.println("Thread 1: Waiting for lock 2..."); 
      synchronized (Lock2) { 
       System.out.println("Thread 1: Holding lock 1 & 2..."); 
      } 
     } 
     } 
    } 
    private static class ThreadDemo2 extends Thread { 
     public void run() { 
     synchronized (Lock2) { 
      System.out.println("Thread 2: Holding lock 2..."); 
      try { Thread.sleep(10); } 
      catch (InterruptedException e) {} 
      System.out.println("Thread 2: Waiting for lock 1..."); 
      synchronized (Lock1) { 
       System.out.println("Thread 2: Holding lock 1 & 2..."); 
      } 
     } 
     } 
    } 
} 

これは、次のサンプル出力を発生します

Thread 1: Holding lock 1... 
Thread 2: Holding lock 2... 
Thread 1: Waiting for lock 2... 
Thread 2: Waiting for lock 1... 

すなわち、デッドロックがあります。しかし、それは次のようになりますように、私たちは第二のスレッドで取得したロックの順序を変更した場合、:

public class TestThread { 
    public static Object Lock1 = new Object(); 
    public static Object Lock2 = new Object(); 

    public static void main(String args[]) { 

     ThreadDemo1 T1 = new ThreadDemo1(); 
     ThreadDemo2 T2 = new ThreadDemo2(); 
     T1.start(); 
     T2.start(); 
    } 

    private static class ThreadDemo1 extends Thread { 
     public void run() { 
     synchronized (Lock1) { 
      System.out.println("Thread 1: Holding lock 1..."); 
      try { Thread.sleep(10); } 
      catch (InterruptedException e) {} 
      System.out.println("Thread 1: Waiting for lock 2..."); 
      synchronized (Lock2) { 
       System.out.println("Thread 1: Holding lock 1 & 2..."); 
      } 
     } 
     } 
    } 
    private static class ThreadDemo2 extends Thread { 
     public void run() { 
     synchronized (Lock1) { 
      System.out.println("Thread 2: Holding lock 1..."); 
      try { Thread.sleep(10); } 
      catch (InterruptedException e) {} 
      System.out.println("Thread 2: Waiting for lock 2..."); 
      synchronized (Lock2) { 
       System.out.println("Thread 2: Holding lock 1 & 2..."); 
      } 
     } 
     } 
    } 
} 

期待どおりに動作し、サンプル出力は次のようになります。

Thread 1: Holding lock 1... 
Thread 1: Waiting for lock 2... 
Thread 1: Holding lock 1 & 2... 
Thread 2: Holding lock 1... 
Thread 2: Waiting for lock 2... 
Thread 2: Holding lock 1 & 2... 

ができ誰かがデッドロックの原因となっている最初のもので何が起こっているのかを私に説明して、なぜ2番目のコードの変更がそれを修正するのですか?

答えて

5

は、最初のケースのための可能なシナリオです:

スレッド1がLock1を取得し、10ミリ秒間スリープ状態になります。スレッド2はLock2を取得し、10ミリ秒間スリープ状態になります。

Lock2を取得するために1回の試行スレッドが、それはスレッド2で取得していますので、後者の場合は、スレッド1

によってロックされているLock1を取得するために、スレッド2試みながら、それを得ることができない、のと仮定しましょう最初のスレッドが実行されます。それはLock1を得ようとしているので、もう1つのスレッドはブロックされていますが、Lock1を取得します。スレッド1はスリープ状態になり、2番目の(ネストされた)同期ブロックに進みます。それはそれを得ることを試みる(まだ自由であるので) - 今彼はの錠を得た。もう一方のスレッドはまだブロックされています。

ロックを(それは同期ブロックを終了するので)解放します。そして、今はJVMが自由に選択するスレッドを決めることができますが、実際には同じロジックは起こりません。

+0

ありがとうございました。私は今、最初のケースを理解することができます。しかし、2番目のケースはまだ少しばかりです。したがってスレッド2は最初のロックを待っています。それがスレッド1によって解放されるとすぐに、どうなりますか? – SexyBeast

+0

@AttitudeMongerスレッド2はそれを取得し、同期ブロックの下の最初のステートメントの実行を開始します。 – Maroun

+0

'System.out.println("スレッド2:ロック1と2を保持しています... ");'?そして、スレッド1によって獲得されたロック2を解放し、 'System.out.println("スレッド1:ロック1と2を保持... ");'? – SexyBeast

1

最初のコードでは、最初のスレッドはLock1を保持し、2番目のスレッドは明らかにLock2を保持しています。次に、互いのロックを取得しようとしますが、他のロックがすでに他のスレッドによって保持されているため、デッドロックが作成されるため、それらは失敗します。

しかし、2番目のコードでは、2番目のスレッドはLock2を保持せず、最初のスレッドが最初のロックを解放するまで何もブロックされません。最初のスレッドは、出力に見られるように、最初のスレッドを取り込んだ後、最初のスレッドを解放します。ここで

2

ここでは、デッドロック防止の一般的な方法であるロックの順序付けについて説明します。あなたの最初のケースで

、スレッドごとにマークされた場所にある現在の命令ポインタと実行の次の順序を考慮してください。今すぐ

Thread 1: 
    obtain lock 1 
===> 
    obtain lock 2 
    Thread 2: 
    obtain lock 2 
===> 
    obtain lock 1 

、スレッド次のロック2を取得するために1回の試行ではなく、ASできロック2はスレッド2によって保持されます。スレッド2はロック1を次に取得しようとしますが、スレッド1によって保持されているためロックできません。これは古典的な循環リソース依存であり、結果としてデッドロックになります。

これを防ぐためのグローバルな方法は、すべてのロックがの合計での順番になっていることを確認することです。ロックは常にその合計順序で取得されます。

この動作は簡単です:すべてのロックの依存関係は、全体の順序で「下向き」であるため、ロックサイクルを持つことはできません。

関連する問題