Подтвердить что ты не робот

Должен ли я выполнять Thread.currentThread(). Interrupt() `before` throw new InterruptedIOException() `?

Я реализую MyInputStream.read() и замечаю, что в этой функции может произойти InterruptedException. После некоторого поиска я обнаружил, что обычно ловить InterruptedException и повторно бросать InterruptedIOException, что-то вроде:

    try {
        ...
    } catch (InterruptedException e) {
        //Thread.currentThread().interrupt(); // <=== ???
        throw new InterruptedIOException();
    }

но только около 50% образцов кода Thread.currentThread().interrupt(). Ну, согласен, что самое худшее, что вы можете сделать с InterruptedException, усвоить его, но следует перепроверить текущий поток до бросая другое исключение?

PRO: один запрос прерывания может иметь несколько "получателей".

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

CONTRA: мы получаем два уведомления о запросе прерывания: состояние прерывания потока и исключение. Изначально существует только одно уведомление: либо прерванный статус потока является истинным, либо генерируется InterruptedException, но не оба.

PRO: никто не проверяет код в отношении исключений i/o, которые могут быть выбраны, а InterruptedIOException отличается от других исключений i/o; a catch(IOException) может усвоить прерванный статус.

PS Похоже на то, что я делаю, проблема, что InterruptedIOException является особым видом IOException, требующим специального обработчика, не будет решена.

PPS (EDIT) Я не могу позволить оригиналу InterruptedException распространяться, потому что InputStream.read() не может выбрасывать InterruptedException (it throws IOException и ничего не бросать). И я не могу предсказать контекст, в котором будет вызываться MyInputStream.read(): экземпляр MyInputStream может быть передан любой библиотечной функции Java или сторонней библиотеки, которая принимает аргумент InputStream.

Что касается старой ошибки, похоже, что она была просто закрыта, а не исправлена; и сама идея прерванного состояния заключается в том, что код будет вести себя по-другому.

4b9b3361

Ответ 1

Я предлагаю бросить ClosedByInterruptException. Хотя он принадлежит библиотеке NIO, он имеет более совершенный API, чем старый InterruptedIOException, что упрощает его обработку. Например:

try {
    ...
} catch (InterruptedException e) {
    close(); // obeying API of ClosedByInterruptException
    Thread.currentThread().interrupt(); // again, obeying API
    throw new ClosedByInterruptException();
}

См. также Thread # interrupt(). Если вместо этого вы хотите перебросить исходное исключение, вы можете использовать:

try {
    ...
} catch (InterruptedException e) {
    throw e;
}

Итак, вы сохраняете трассировку стека. Статус прерывания остается открытым в этом случае, как предполагает API для InterruptedException.

Ответ 2

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

Если что-то скачкообразно скажется на флаге прерывания, тогда да. В противном случае это не имеет значения.

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

По моему чтению анализа ошибка, с которой вы связаны, относится только к Java 6 и более ранним версиям и только для платформы Solaris. Вы можете, вероятно, скинуть его сейчас. (Если у вас нет клиента с deeeep карманами, вы не должны делать значительное приложение для Java 6 или ранее.)

CONTRA: мы получаем два уведомления о запросе прерывания: состояние прерывания потока и исключение.

Это качественно разные виды уведомлений...

PS Похоже на то, что я делаю, проблема, что InterruptedIOException - это особый вид IOException, требующий специального обработчика, не будет разрешаться.

На самом деле лучшей стратегией может быть установка прерванного флага в catch для InterruptedIOException... или просто разрешение распространения исходного Interrupted.

Ответ 3

Из-за следующих соображений:

  • InterruptedException НЕ ДОЛЖЕН быть проглочен,

  • any IOException (и, в частности, InterruptedIOException) МАЙ быть проглоченным, то есть потребляемым сторонним кодом

  • IOException предназначен для информирования о событиях, которые происходят с i/o, а не об изменениях в состоянии потока

  • Некоторый код, который мы не можем контролировать, может либо установить, либо очистить состояние прерывания потока перед тем, как бросать или повторно бросать InterruptedIOException

Я решил, что:

  • текущий поток ДОЛЖЕН быть переработан, прежде чем бросать InterruptedIOException.
  • обработка кода InterruptedIOException НЕ ДОЛЖНА принимать какое-либо конкретное состояние состояния прерывания потока.
  • это должно быть документировано:

    @throws InterruptedIOException if the current thread is interrupted (the thread
            interrupted status is true when InterruptedIOException is thrown)
    @throws IOException if this stream is closed or another IOException occurs.
    
    Note that due to possible interference from 3rd-party code, handlers 
    of InterruptedIOException should not assume any particular state
    of the thread interrupted status when they are invoked.