2016-03-28 4 views
0

В приведенном ниже примере я пытаюсь изящно завершить оба потока. Потребительский поток прерывается во время сна, который должен установить флаг isInterrupted равным true. Однако проверка на Thread.currentThread(). IsInterrupted() в цикле while по-прежнему возвращает = false, поскольку она не прерывает поток потребителей.Прерывание потока во время сна

Скопируйте и вставьте следующий код в IDE и проверить:

public class ThreadInterruptExample { 

public static void main(String[] args) throws InterruptedException { 
    LinkedBlockingQueue<String> queue = new LinkedBlockingQueue<String>(1); 
    ThreadInterruptExample ie = new ThreadInterruptExample(); 
    Producer producer = ie.new Producer(queue); 
    Consumer consumer = ie.new Consumer(queue, producer); 
    producer.start(); 
    consumer.start(); 
    Thread.sleep(1000); 
    producer.cancel(); 
    consumer.cancel(); 
} 

class BaseQueue extends Thread { 
    protected final BlockingQueue<String> queue; 

    public BaseQueue(BlockingQueue<String> queue) { 
     this.queue = queue; 
    } 

    public void cancel() { 
     System.out.println(this.getName() + " - Shutting down"); 
     interrupt(); 
    } 
} 

class Producer extends BaseQueue { 
    private final List<String> messages = Arrays.asList("a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", 
      "r", "s", "t", "u", "v", "w", "x", "y", "z"); 

    public Producer(BlockingQueue<String> queue) { 
     super(queue); 
     this.setName("Producer"); 
    } 

    public void run() { 
     try { 
      for (String message : messages) { 
       System.out.println(this.getName() + ": Sending " + message); 
       queue.put(message); 
      } 
     } catch (InterruptedException e) { 
      System.out.println(this.getName() + " - InterruptedException occurred"); 
     } 
    } 
} 

class Consumer extends BaseQueue { 
    private final BaseQueue producer; 

    public Consumer(BlockingQueue<String> queue, BaseQueue producerQueue) { 
     super(queue); 
     this.setName("Consumer"); 
     producer = producerQueue; 
    } 

    @Override 
    public void run() { 
     while (!Thread.currentThread().isInterrupted()) { 
      System.out.println(this.getName() +": Consumer Running"); 
      String message = ""; 
      try { 
       Thread.sleep(1500); 
       message = queue.take(); 
       System.out.println(this.getName() + ": Recevied " + message); 
       if (message.equals("pill")) { 
        producer.cancel(); 
        this.cancel(); 
       } 
      } catch (InterruptedException e) { 
       System.out.print(this.getName() + ": Exception occurred for: " + message); 
       e.printStackTrace(); 
      } 
     } 
    } 

} 

}

ответ

3

Вы выбрасываете прерывание, когда вы ловите InterruptedException. Существует два решения.

while (!Thread.currentThread().isInterrupted()) { 
    try { 
     Thread.sleep(1500); 

    } catch (InterruptedException e) { 
     Thread.currentThread.interrupt(); 
    } 
} 

или намного проще только перехватить исключение вне цикла.

try { 
    while (!Thread.currentThread().isInterrupted()) { 
     Thread.sleep(1500); 
    } 
} catch (InterruptedException e) { 
    Thread.currentThread.interrupt(); 
} 

EDIT: Я полагаю, что это просто упражнение, как это было бы гораздо проще использовать ExecutorService

public static void main(String[] args) throws InterruptedException { 
    ExecutorService service = Executors.newSingleThreadExecutor(); 

    for (String message : "a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z".split(",")) { 
     System.out.println(getThreadName() + ": Sending " + message); 
     service.submit(() -> { 
      System.out.println(getThreadName() + ": Recevied " + message); 
      try { 
       Thread.sleep(500); 
      } catch (InterruptedException e) { 
       System.out.println("--- Interrupted"); 
      } 
     }); 
    } 
    service.shutdown(); 
    service.awaitTermination(1, TimeUnit.SECONDS); 
    service.shutdownNow(); 
} 

public static String getThreadName() { 
    return Thread.currentThread().getName(); 
} 

отпечатки

main: Sending a 
main: Sending b 
main: Sending c 
main: Sending d 
main: Sending e 
main: Sending f 
main: Sending g 
main: Sending h 
main: Sending i 
main: Sending j 
main: Sending k 
main: Sending l 
main: Sending m 
main: Sending n 
main: Sending o 
main: Sending p 
main: Sending q 
main: Sending r 
main: Sending s 
main: Sending t 
main: Sending u 
main: Sending v 
main: Sending w 
main: Sending x 
main: Sending y 
main: Sending z 
pool-1-thread-1: Recevied a 
pool-1-thread-1: Recevied b 
--- Interrupted 
+0

Спасибо за альтернативный пример. И ваши предложения работают. Что я не понимаю, почему возникает необходимость повторного прерывания исключения в Потребителе. Я уже назвал его однажды user.cancel() ->, который вызовет прерывание(). Отсюда почему это исключает. Зачем мне это делать снова, используя: Thread.currentThread.interrupt(); ? –

+1

@ShivamSinha После запуска InterruptedException сигнал очищается, поэтому Thread может использоваться для чего-то другого. Предполагается, что вы обработали прерывание в блоке 'catch', и нет необходимости оставлять его в этом состоянии. Примечание. Невозможно отключить прерывание. –

1

Как указано в javadocs

Если этот поток заблокирован при вызове методов wait(), wait (long) или wait (long, int) класса Object или join(), join (long), join (long , int), sleep (long) или sleep (long, int), методы этого класса, тогда его статус прерывания будет очищен, и он получит InterruptedException.

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

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