Почему проглатывание InterruptedException нормально для подклассов Thread? - PullRequest
4 голосов
/ 20 мая 2009

В статье Брайана Гетца о том, как обрабатывать InterruptedException , выделяется один абзац:

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

Я не понимаю этого. Возможно, причина в том, что Runnable обрабатывается пулом потоков, тогда как поток - это то, что вы запускаете самостоятельно?

Ответы [ 3 ]

4 голосов
/ 20 мая 2009

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

Я ненавижу InterruptedException, я думаю, что проверенные исключения дают плохое имя, и эта статья не меняет эту точку зрения. Если было так важно, чтобы это исключение передавало стек вызовов, Runnable.run () должен был объявить его в объявлении метода, чтобы вы могли просто перебросить его, или это должно было быть непроверенное исключение по той же причине, что SecurityException является непроверенным исключение.

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

3 голосов
/ 20 мая 2009

Я бы сказал, что расширение Thread было ненужным, и поэтому реализация Runnable предпочтительнее.

Но важно то, что код знает, что поток собирается выйти. Если ваш код является частью какого-то общего интерфейса обратного вызова, вы не можете знать, как его используют. Вы можете быть переданы в пул потоков (действительно, нам, вероятно, следует использовать пулы, а не создавать Thread s в неподходящих точках в коде). OTOH, обычно Runnable - это анонимный внутренний класс и, следовательно, на уровне источника, часть включающего метода, который действительно знает, что происходит.

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

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

Библиотеки, как правило, неправильно обрабатывают прерывания. ИМО, прерывания не имеют смысла. Без них жизнь была бы намного проще, к сожалению, они дают о себе знать.

2 голосов
/ 17 июля 2009

Я согласен с другими, что разница в том, контролируете ли вы эту тему или нет. Если вы расширили поток, это в значительной степени само собой разумеется, что вы можете контролировать этот поток. С другой стороны, если ваш код просто Runnable, он может быть запущен в заимствованном потоке (например, из пула потоков), которым вы не владеете. Поглощая исключения и , не восстанавливающие статус прерывания, вы лишаете код, находящийся выше, возможности распознать прерывание и действовать на него.

InterruptedException, будучи проверенным исключением, я думаю, это хорошая вещь. InterruptedException - это способ запроса отмены задач. Предположим, кто-то написал задачу в форме Runnable, которая включает метод блокировки, который генерирует исключение InterruptedException. Если это не было проверенное исключение, если вы не проявляете осторожности, вы можете не подумать о том, чтобы действовать на InterruptedException (то есть отмене) и делать свою собственную очистку .

public class MyTask implements Runnable {
    public void run() {
        while (someCondition) {
            Object value = someBlockingQueue.take();
            // act on the value and loop back
        }
    }
}

Поскольку InterruptedException является проверенным исключением, то, как моя задача должна реагировать на прерывание (отмену), является передней и центральной.

public class MyTask implements Runnable {
    public void run() {
        while (someCondition) {
            try {
                Object value = someBlockingQueue.take();
                // act on the value and loop back
            } catch (InterruptedException e) {
                // I'm being cancelled; abort
                cleanUp();
                // restore the interrupt
                Thread.currentThread().interrupt();
                break;
            }
        }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...