Является Thread.interrupt () злом?

Товарищ по команде предъявил следующую претензию:

"Thread.interrupt() по сути повреждается и (почти) никогда не должен использоваться".

Я пытаюсь понять почему дело обстоит так.

Действительно ли это - известная лучшая практика, чтобы никогда использовать Thread.interrupt()? Можно ли представить свидетельства, почему они повреждаются / багги и не должны использоваться для написания устойчивого многопоточного кода?

Отметьте - я не интересуюсь этим вопросом, если это "симпатично" от консерванта дизайна. Мой вопрос - действительно ли это - багги?

30
задан user2428118 30 April 2015 в 10:48
поделиться

5 ответов

Короткая версия:

Известно ли, что это лучшая практика, никогда не позволяющая использовать Thread.interrupt()?

Нет.

Можешь ли ты предоставить доказательство того, почему он сломан / багги, и не должен использоваться для написания робастный многопоточный код?

Обратное верно: он критичен для многопоточного кода.

См. пример Листинга 7.7 в Java Concurrency in Practice.

Более длинная версия:

Здесь мы используем этот метод в одном конкретном месте: обработка Прерванные перехваты . Это может показаться немного странным, но вот как это выглядит в коде:

try {
    // Some code that might throw an InterruptedException.  
    // Using sleep as an example
    Thread.sleep(10000);
} catch (InterruptedException ie) {
    System.err.println("Interrupted in our long run.  Stopping.");
    Thread.currentThread().interrupt();
}

Это делает для нас две вещи:

  1. Это позволяет избежать поедания исключения из прерывания. Обработчики автоматического исключения в IDE всегда предоставляют что-то вроде ie.printStackTrace(); и комментария "TODO: Что-то полезное нужно сделать здесь!".
  2. Восстанавливает статус прерывания, не заставляя проверенное исключение в этом методе. Если сигнатура метода, который вы реализуете, не имеет бросает пункт InterruptedException, то это ваша другая опция для распространения этого прерывистого статуса.

Один из комментаторов предложил использовать исключение без флажка "чтобы заставить поток погибнуть". Это предполагает, что мне заранее известно, что внезапное прерывание нити является правильным поступком. Я не знаю.

Цитирую Брайана Гетца из JCIP на странице перед перечислением, упомянутым выше:

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

Например, представьте, что я сделал это:

} catch (InterruptedException ie) {
    System.err.println("Interrupted in our long run.  Stopping.");
    // The following is very rude.
    throw new RuntimeException("I think the thread should die immediately", ie);
}

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

Например, вот что все остальные в команде должны были бы сделать немедленно:

try {
    callBobsCode();
} catch (RuntimeException e) { // Because Bob is a jerk
    if (e.getCause() instanceOf InterruptedException) {
        // Man, what is that guy's problem?
        interruptCleanlyAndPreserveState();
        // Restoring the interrupt status
        Thread.currentThread().interrupt();
    }
}

Прерывистое состояние более важно, чем любое конкретное Прерывание-перехват . Для конкретного примера почему, смотрите javadoc для Thread.interrupt():

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

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

40
ответ дан 27 November 2019 в 23:32
поделиться

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

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

Я рекомендую Java Concurrency in Practice для более подробного ознакомления с правильным и безопасным его использованием.

.
16
ответ дан 27 November 2019 в 23:32
поделиться

Основная проблема с Thread.interrupt() заключается в том, что большинство программистов не знают о скрытых подводных камнях и используют их неправильно. Например, при обработке прерывания существуют методы, которые очищают флаг (так что статус теряется).

Кроме того, вызов не всегда сразу же прерывает поток. Например, когда оно зависает в какой-то системной рутине, ничего не произойдет. На самом деле, если поток не проверит флаг и никогда не вызовет метод Java, который бросит InterruptException, то прерывание потока не будет иметь никакого эффекта.

.
11
ответ дан 27 November 2019 в 23:32
поделиться

Нет, это не багги. На самом деле, это основа того, как вы останавливаете потоки на Java. Он используется в фреймворке исполнителя из java.util.concurrent - см. реализацию java.util.concurrent.FutureTask.Sync.innerCancel.

Что касается неудачи, то я никогда не видел ее неудачной, и я ее широко использую.

.
3
ответ дан 27 November 2019 в 23:32
поделиться

THe проблема не в том, что реализация не багги, а в том, что ваш поток находится в неизвестном состоянии, когда он прерывается, и это может привести к непредсказуемому поведению.

.
-3
ответ дан 27 November 2019 в 23:32
поделиться
Другие вопросы по тегам:

Похожие вопросы: