2016-05-06 7 views
0

Javaスレッドで競合状態を作成する同時実行性とデッドロックを作成します。 私はReentrantLockを使用しますが、InterruptedExceptionは投げません。なぜReentrantLockはInterruptedExceptionをスローしないのですか?

今はデッドロックですが、lockInterruptiblyを使用していますが、InterruptedExceptionをスローしません。 l1.lock()l2.lock()

public class Test { 

    public static void main(String[] args) throws InterruptedException { 

     final Object o1 = new Object(); 
     final Object o2 = new Object(); 

     final ReentrantLock l1 = new ReentrantLock(); 
     final ReentrantLock l2 = new ReentrantLock(); 

     Thread t1 = new Thread() { 
      public void run() { 
       try { 
        l1.lockInterruptibly(); 
        System.out.println("I am in t1 step 1 " + o1.toString()); 
        Thread.sleep(1000); 
        l2.lock(); 
        try { 
         System.out.println("I am in t1 step 2 " + o2.toString()); 
        } finally { 
         l2.unlock(); 
        } 

       } catch (InterruptedException e) { 
        e.printStackTrace(); 
       } 
      } 
     }; 

     Thread t2 = new Thread() { 
      public void run() { 
       try { 
        l2.lockInterruptibly(); 
        System.out.println("I am in t2 step 1 " + o2.toString()); 
        Thread.sleep(1000); 
        l1.lock(); 
        try { 
         System.out.println("I am in t2 step 2 " + o1.toString()); 
        } finally { 
         l1.unlock(); 
        } 
       } catch (InterruptedException e1) { 
        e1.printStackTrace(); 
       } 
      } 
     }; 

     t1.start(); 
     t2.start(); 
     Thread.sleep(2000); 
     t1.interrupt(); 
     t2.interrupt(); 
     t1.join(); 
     t2.join(); 

    } 
} 
+0

「競争」は「競合状態」であるべきだと思います... – Sayakiss

答えて

1

2つのスレッドは、行にデッドロックされています。あなたがそれらを中断すると、反応しません。 lockInterruptibly()とすべてのlock()コールを交換すると例外が発生します。

編集:私はあなたが好きな競合状態を生成します単純な例準備 :

Thread 1 won 
Thread 2 interrupted 
:このコードで

public class Test { 

    public static void main(String[] args) throws InterruptedException { 

     final ReentrantLock l1 = new ReentrantLock(); 
     final Random rn = new Random(); 

     Thread t1 = new Thread() { 
      public void run() { 
       try { 
        Thread.sleep(rn.nextInt(1000)); //wait 0-999 ms 
        l1.lockInterruptibly(); 
        System.out.println("Thread 1 won"); 
       } catch (InterruptedException e) { 
        System.out.println("Thread 1 interrupted"); 
       } 
      } 
     }; 

     Thread t2 = new Thread() { 
      public void run() { 
       try { 
        Thread.sleep(rn.nextInt(1000)); //wait 0-999 ms 
        l1.lockInterruptibly(); 
        System.out.println("Thread 2 won"); 
       } catch (InterruptedException e1) { 
        System.out.println("Thread 2 interrupted"); 
       } 
      } 
     }; 

     t1.start(); 
     t2.start(); 
     Thread.sleep(2000); 
     t1.interrupt(); 
     t2.interrupt(); 
     t1.join(); 
     t2.join(); 

    } 
} 

を、あなたはそれを実行し、ランダムに1つの出力のたびに取得します生成されるランダムに応じて

または

Thread 2 won 
Thread 1 interrupted 

数字。

+0

ありがとう:-)。競争状態の良いケースです。 – jsohpill

1

問題は、各スレッドが2つのロックを取得しようとしていることです。

   // Thread 1. 
       l1.lockInterruptibly(); 
       // .... 
       l2.lock(); 


       // Thread 2. 
       l2.lockInterruptibly(); 
       // .... 
       l1.lock(); 

各スレッドはロックを取得し、もう一方のスレッドが既に保持しているロックを取得しようとします。これはデッドロックと呼ばれます。

java.lang.InterruptedExceptionスレッドが待機しているロック(2番目のスレッド)が割り込み可能なロックではないため、java.lang.InterruptedExceptionが表示されません。

修正これで:

   // Thread 1. 
       l1.lockInterruptibly(); 
       // .... 
       l2.lockInterruptibly(); 


       // Thread 2. 
       l2.lockInterruptibly(); 
       // .... 
       l1.lockInterruptibly(); 
+0

ありがとう:-)、あなたは正しいです、私はすべてのスレッドの2番目のロックを使用するlockInterruptiblyを使用する必要があります。 – jsohpill

0

リエントラントがすでにロックを保持している単一のスレッドがそれを取り戻すことができます。

あなたのケースでは、2つの異なるスレッドが作成されています。

これはと呼ばれます。リエントラントロックアウトは、デッドロックとネストされたモニタロックアウトに似た状況です。

あなたはスレッドT1に

  l1.lockInterruptibly(); 
      System.out.println("I am in t1 step 1 " + o1.toString()); 
      Thread.sleep(1000); 
      l2.lockInterruptibly(); 

とスレッドT2に

  l2.lockInterruptibly(); 
      System.out.println("I am in t2 step 1 " + o2.toString()); 
      Thread.sleep(1000); 
      l1.lockInterruptibly(); 
0

これをすることによって修正することができます任意の体はなぜ私に言うことができるそれは、InterruptedExceptionあるをスローしませんか?たぶん

ReentrantLockを作成した目的は、相互排他ですので。

あなたのプログラム内のスレッドが1秒間に数回以上ロックされたミューテックスを保持していると、それは悪いコードの匂いです。 lock.lock()コール割り込みを作る

は、それを使用するすべてのプログラムが複雑になる:あなたがロックをロックしたいすべての場所は、あなたがInterruptedExceptionのためのハンドラを記述する必要があると思います。

私の推測では(そしてそれはそれがすべてです)著者は、彼らはすべてのプログラマはちょうど一部プログラマが悪いデザインでReentrantLockを使用することができるように、それらの余分割り込みハンドラを記述する必要は作るべきではないと思ったということです。

関連する問題