2016-05-06 7 views
0

Я хочу создать условие гонки в потоке Java Concurrency и создать тупик. Я использую 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(), вы получите исключение.

EDIT: Я подготовил простой пример, который будет генерировать состояние гонки, как вы хотите:

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

Повторный вход означает, что один поток, который уже имеет блокировку, может вернуть его.

В вашем случае создаются две разные темы.

Это называется Блокировка ретентата, это ситуация, подобная тупиковой ситуации и блокировка локального монитора.

вы можете исправить это в Thread t1

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

и t2 Thread

  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 в плохих конструкций.