2017-01-03 6 views
3

私のコードにデッドロックのシナリオがありました。次のテストコードでシナリオを再現しました(行番号のコメントも参照してください)。Java:ロックがnullの場合、なぜこれがデッドロックですか?

私は3つのタスクを取る1 ExecuterService、2つのタスクは、それがnull値を持つ必要が初期化されていない同じオブジェクトの上に同期ブロックを持っています。

synchronized(null){}はjavaで許可されていないので、私はline-2にエラーがあります。しかし、これはデッドロックで実行されました。すなわち、最初の2つのタスクは第3のタスクによって待機されていた。

今変更した場合line-1からObject lock = new Object();にコードは完璧にデッドロック(出力2)なしで動作します。初期化されていないmutexオブジェクトを提供するとき、JVMで正確に何が起こっているのか疑問に思っています。 JVMがすべてのタスクで共有される静的なコピーを作成しているように見えます。したがって、デッドロック

public class Test { 
    Object lock; //line -1 
    Integer a = 10; 

    public static void main(String[] arg) { 
     new Test().doIt(); 
    } 

    public void doIt() { 
     ExecutorService service = Executors.newFixedThreadPool(3); 

     service.submit(new Runnable() { 
      public void run() { 
       synchronized (Test.this.lock) { //line -2 
        try { 
         Thread.sleep(1000 * 5); 
        } catch (InterruptedException e) { 
         // TODO Auto-generated catch block 
         e.printStackTrace(); 
        } 
        Test.this.a = (int) Thread.currentThread().getId(); 
        System.out.println(a + " " + Thread.currentThread().getId()); 

       } 
      } 
     }); 

     service.submit(new Runnable() { 
      public void run() { 
       synchronized (Test.this.lock) { 
        try { 
         Thread.sleep(1000 * 5); 
        } catch (InterruptedException e) { 
         // TODO Auto-generated catch block 
         e.printStackTrace(); 
        } 
        Test.this.a = (int) Thread.currentThread().getId(); 
        System.out.println(a + " " + Thread.currentThread().getId()); 

       } 
      } 
     } 

     ); 

     service.submit(new Runnable() { 
      public void run() { 
       Test.this.a = (int) Thread.currentThread().getId(); 
       while (true) { 
        try { 
         Thread.sleep(1 * 1000); 
        } catch (InterruptedException e) { 
         // TODO Auto-generated catch block 
         e.printStackTrace(); 
        } 
        System.out.println(a + " Main"); 
       } 
      } 
     }); 

    } 
} 

出力-1

11 Main 
11 Main 
11 Main 
11 Main 
11 Main 
11 Main 
11 Main 
11 Main 
11 Main 
11 Main 
11 Main 
. 
. 
. 

出力-2

11 Main 
11 Main 
11 Main 
11 Main 
9 9 
9 Main 
9 Main 
9 Main 
9 Main 
9 Main 
10 10 
10 Main 
10 Main 
. 
. 
. 

答えて

7

あなたはデッドロックを持っていない - あなたが予想されるだけのようなエラーがあります。 1番目と2番目のタスクはNullPointerExceptionをスローし、3番目のタスクのみを実行します。

run()の本文をtry/catchの文で囲むと、これが表示されます。

+0

ああ、例外は捕まえられずに印刷されています。とった。そんなに愚かな私... –

+0

@MangatRaiModi:まあ、それはあまりにも静かなことは残念です - それは問題のためのレシピ、IMOです。エラーリスナーなどを登録する簡単な方法があればうれしいでしょう... submitによって返された 'Future'をチェックして、それが完了したことを確認できますが、エラーはありません。あなたは' get() 'もちろんです。 –

+0

ありがとう、チェックされていない例外は常に痛みです。 –

3

例外はエグゼキュータ・スレッドでスローされ、キャッチまたは問合せを行わないと表示されません。

Future<?> f = service.submit(new Runnable() { ... } 

を、メインの終わりに:たとえば、あなたが書くことができ

try { 
    f.get(); 
} catch (ExecutionException | InterruptedException e) { 
    e.printStackTrace(); 
} 

あなたにNPEを示すこと。

関連する問題