2016-05-06 68 views
0

我想在Java線程中創建競爭條件併發並創建死鎖。 我使用ReentrantLock,但它不會拋出InterruptedException。爲什麼java ReentrantLock不拋出InterruptedException?

現在是死鎖,我使用lockInterruptibly,但它不會拋出InterruptedException,任何機構可以告訴我爲什麼?

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個線程被死鎖在線路:l1.lock()l2.lock()。所以當你打斷他們時,他們不會反應。如果您將所有lock()呼叫替換爲lockInterruptibly(),您將會得到例外。

編輯: 我準備了簡單的例子,將產生競爭條件,只要你想:

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(); 

    } 
} 

有了這個代碼,你會每次隨機獲得兩個輸出之一,你運行它:

Thread 1 won 
Thread 2 interrupted 

Thread 2 won 
Thread 1 interrupted 

根據所產生的隨機數字。

+0

謝謝:-)。競爭條件的好例子。 – jsohpill

1

你的問題是每個線程都試圖獲取兩個鎖。

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


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

因此,每個線程抓住一個鎖,然後試圖抓住另一個線程已經擁有的鎖。這被稱爲僵局。

您沒有看到java.lang.InterruptedException,因爲線程正在等待的鎖定(第二個)不是可中斷的鎖定。

修復此有:

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


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

謝謝你:-),你是對的,我不得不在每個線程使用第二個鎖時使用lockInterruptibly。 – jsohpill

0

折返意味着,已經持有一個鎖一個線程可以重考。

在你的情況下,有兩個不同的線程創建。

這叫做再入境鎖定,是一種類似死鎖和嵌套監視器鎖定的情況。

您可以通過在線程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創建的目的是互斥

任何時候,如果程序中的某個線程持有的鎖定時間超過一秒鐘的一小部分,那麼這是一種糟糕的代碼異味。

使lock.lock()調用中斷會使所有使用它的程序複雜化:每個你想要鎖定的地方,你都必須爲InterruptedException寫一個處理程序。

我的猜測(而這一切是)是,作者認爲他們不應該讓所有的程序員都寫這些額外的中斷處理程序只是讓一些程序員可以在惡劣的設計中使用ReentrantLock

相關問題