Зачем вызывать Thread.currentThread.interrupt() в блоке InterruptException catch?

Зачем вызывать метод Thread.currentThread.interrupt() в блоке catch?

Ответ 1

Это делается для сохранения состояния.

Когда вы ловите InterruptException и проглатываете его, вы по существу препятствуете тому, чтобы какие-либо методы более высокого уровня/группы потоков замечали прерывание. Это может вызвать проблемы.

Вызывая Thread.currentThread().interrupt(), вы устанавливаете флаг прерывания потока, поэтому обработчики прерываний более высокого уровня заметят его и могут обрабатывать его соответствующим образом.

Java Concurrency на практике более подробно обсуждается в главе 7.1.3: Ответ на прерывание. Его правило:

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

Ответ 2

Я думаю, что этот образец кода делает вещи немного ясными. Класс, выполняющий задание:

   public class InterruptedSleepingThread extends Thread {

        @Override
        public void run() {
            doAPseudoHeavyWeightJob();
        }

        private void doAPseudoHeavyWeightJob() {
            for (int i=0;i<Integer.MAX_VALUE;i++) {
                //You are kidding me
                System.out.println(i + " " + i*2);
                //Let me sleep <evil grin>
                if(Thread.currentThread().isInterrupted()) {
                    System.out.println("Thread interrupted\n Exiting...");
                    break;
                }else {
                    sleepBabySleep();
                }
            }
        }

        /**
         *
         */
        protected void sleepBabySleep() {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                //e.printStackTrace();
                Thread.currentThread().interrupt();
            }
        }
    }

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

   public class InterruptedSleepingThreadMain {

        /**
         * @param args
         * @throws InterruptedException
         */
        public static void main(String[] args) throws InterruptedException {
            InterruptedSleepingThread thread = new InterruptedSleepingThread();
            thread.start();
            //Giving 10 seconds to finish the job.
            Thread.sleep(10000);
            //Let me interrupt
            thread.interrupt();
        }

    }

Попробуйте вызвать прерывание, не устанавливая статус.

Ответ 3

Примечание:

http://download.oracle.com/javase/7/docs/technotes/guides/concurrency/threadPrimitiveDeprecation.html

Как остановить поток, который ожидает длительные периоды (например, для ввода)?

Для того, чтобы этот метод работал, критически важно, чтобы любой метод, который ловил исключение прерывания и не был готов к его устранению, немедленно повторяет исключение. Мы говорим о повторных попытках, а не о повторениях, потому что не всегда можно перестроить исключение. Если метод, который улавливает InterruptedException, не объявляется, чтобы выбрасывать это (отмеченное) исключение, тогда он должен "перевоспитать себя" следующим заклинанием:

Thread.currentThread().interrupt();

Это гарантирует, что Thread будет ререйзить InterruptedException, как только он сможет.

Ответ 4

Я считаю это плохой практикой или, по крайней мере, немного рискованно. Обычно методы более высокого уровня не выполняют блокирующие операции, и они никогда не будут видеть InterruptedException. Если вы замаскируете его во всех местах, где вы выполняете прерывистую операцию, вы никогда не получите его.

Единственное логическое обоснование для Thread.currentThread.interrupt() и не возбуждение какого-либо другого запроса об исключении или сигнальном прерывании любым другим способом (например, установка локальной переменной переменной interrupted в основной петле потока) - это ситуация, когда вы действительно ничего не можете сделать за исключением, как в блоках finally.

См. ответ Péter Török, если вы хотите лучше понять последствия вызова Thread.currentThread.interrupt().