2015-03-21 2 views
0

Я пытаюсь реализовать блокирующую очередь (только на стороне потребителя) с помощью ReentrantLock и условия, но я запускаю состояние, когда JVM не завершается , Странно, что один поток прерывается, а другой - нет. Я уверен, что ошибаюсь, но просто не могу понять, что.Прерывание, вызванное потоком, не выбрасывает прерывание Исключение при блокировке потока

EDIT:

Главный Вопрос: Почему только один поток бросить InterruptedException, когда обе нити блокирующие на condition.await

Так что ниже код является только примером, который я создал. Основная проблема заключалась в том, чтобы разработать реализацию производителя-потребителя, в которой мне пришлось создать класс моделирования, который породил два вида потоков, клиентов и поваров, которые были синхронизированы на основе блокировки реентера. После того, как некоторые операции были выполнены (клиенты добавили заказы и куки, выполняя выполнение этих заказов), я вызываю соединение по потокам клиентов, чтобы убедиться, что все заказы обработаны, а затем, чтобы остановить потоки кука, я вызывал прерывание в потоках кука, чтобы их прервать , Но только один поток выдает прерывание, а второе - нет. Почему это? поскольку оба потока блокируются в ожидании.

Мой код выглядит следующим образом: класс

темы:

public class InterruptedThread implements Runnable{ 

    private final Lock lock; 
    private final Condition condition; 
    private final Queue<Integer> orderQueue; 


    public InterruptedThread(Lock lock, Condition condition,Queue<Integer> orderQueue) 
    { 
     this.lock = lock; 
     this.condition = condition; 
     this.orderQueue = orderQueue; 
    } 

    @Override 
    public void run() { 

     try{ 
     while(true) 
     { 
      this.lock.lockInterruptibly(); 
      while(orderQueue.size() == 0 && !Thread.currentThread().isInterrupted()) 
      { 
        System.out.println("Inside blocking wait" + Thread.currentThread().getName()); 
        condition.await(); 
      } 

      int i = orderQueue.poll().intValue(); 
      System.out.println("Value read:" + i + "by thread" + Thread.currentThread().getName()); 
      this.lock.unlock(); 


     } 
     } 
     catch(InterruptedException ex) 
     { 
      System.out.println("Interrupted exception" + Thread.currentThread().getName()); 
      this.condition.signalAll(); 
      Thread.currentThread().interrupt(); 

     } 

    } 

} 

Основной класс:

public class ExplicitLockCondition { 

    /** 
    * @param args the command line arguments 
    */ 
    public static void main(String[] args) { 
     // TODO code application logic here 

     Queue<Integer> orderQueue = new LinkedList<>(); 
     Lock lock = new ReentrantLock(); 
     Condition testCondition = lock.newCondition(); 

     Thread[] ths = new Thread[2]; 
     for(int i=0; i<ths.length;i++) 
     { 
      ths[i] = new Thread(new InterruptedThread(lock, testCondition,orderQueue)); 
      ths[i].start(); 
     } 

     lock.lock(); 

     orderQueue.add(1); 
     lock.unlock(); 

     lock.lock(); 
     orderQueue.add(2); 
     lock.unlock(); 

     try { 
      Thread.currentThread().sleep(5000); 
     } catch (InterruptedException ex) { 
      Logger.getLogger(ExplicitLockCondition.class.getName()).log(Level.SEVERE, null, ex); 
     } 

     lock.lock(); 
     orderQueue.add(-99); 
     lock.unlock(); 


     for(int i=0; i<ths.length;i++) 
     { 
      ths[i].interrupt(); 

     } 
     System.out.println("After loop exited!!!"); 
     for(int i=0; i<ths.length;i++) 
     { 
     System.out.println("Interrupted thread:" + ths[i].getName() +"with interrupt flag:" + ths[0].isInterrupted()); 
     } 

     for(int i=0; i<ths.length;i++) 
     { 
      try { 
       ths[i].join(); 
      } catch (InterruptedException ex) { 
       Logger.getLogger(ExplicitLockCondition.class.getName()).log(Level.SEVERE, null, ex); 
      } 
     } 

     System.out.println("Program exited!!!"); 

    } 

} 

ответ

0

Вы

condition.await(); 

но единственное место, где вы signal находится в блоке catch.

В типичном запуске приложения, ваш InterruptedThread (давайте назовем его it1) войдет в цикл while и await на condition, поставив себя в состоянии ожидания. Ваша нить main будет делать кучу вещей и в конечном итоге прерывать it1. Вы обратите внимание на Javadoc из Condition#await() утверждает

Во всех случаях, прежде чем этот метод может возвращать текущий поток должен повторно приобрести замок, связанный с этим условием.

Так нить it2 выкупает замок и потому, что это было прервано

Если текущий поток:

  • имеет свой прервала статус устанавливается на входе этого метода; или
  • прерываются во время ожидания и прерывание потока суспензии поддерживается,

затем InterruptedException брошен и прервал статус текущего потока очищается.

Таким образом, исполнение оставляет блок while и переходит на catch. За это время ваша нить it2 все еще владеет замком, так как ничего не было unlock ed it. catch блок затем вызывает

this.condition.signalAll(); 

который сигнализирует о condition. Тема it1 затем завершается нормально. Однако Lock все еще заперта, и ничто не может его приобрести поэтому другие InterruptedThread не может продолжаться внутри его

condition.await(); 

Вы в основном должны управлять блокировки и разблокировки вашего Lock лучше вашего.

+0

Спасибо, замок был не сдалась по этой теме, я добавил лучше разблокировки кода в настоящее время. –

+0

@SotiriosDelimanolis У меня есть аналогичный вопрос о 'InterruptedException' [здесь] (http://stackoverflow.com/questions/29159184/how-can-i-interrupt-resttemplate-call-as-soon-as-my-thread-is - прерывается), что касается прерывания вызовов «RestTemplate». Если возможно, вы можете помочь мне. Я знаю, что вы очень помогли мне в решении другого вопроса RestTemplate, чтобы вы могли помочь мне в этом. Любая помощь будет оценена. Я все еще не в состоянии найти хороший способ справиться с моей текущей проблемой. – john

+0

@SotiriosDelimanolis Вы рядом? Извините, что снова связался с вами. если у вас есть какое-то время сегодня, мы можем поговорить по моему глупому вопросу, на котором я застрял в течение длительного времени. – john

0

а) вы никогда не сигнализировать состояние после того, как вы вставляете значение очереди

б) ваш поток оставит

while(orderQueue.size() == 0 && !Thread.currentThread().isInterrupted()) 

если она была прервана, а затем пытался опрашивать значение из очередь. Если там нет значения, null будет возвращен, и вы получите исключение исключенного null-указателя, но блокировка никогда не будет разблокирована.

Allways

lock.lock()l 
try { 
... 
} finally { 
lovk.unlovk(); 

}

+0

Спасибо, я пошел по шаблону, который вы предложили реорганизовать мой код, теперь он работает. –

Смежные вопросы