Зачем использовать Thread.currentThread().isInterrupted () вместо Thread.interrupted () при реализации Runnable?

в stackoverflow я часто вижу использование Thread.currentThread().isInterrupted(). При реализации Runnable и используя его в цикле while, например:

public void run() {
  while(!Thread.currentThread().isInterrupted()) { ... }
}

есть ли разница в использовании Thread.interrupted() (кроме этого interrupted флаг очищается при использовании interrupted())?

я тоже видел Thread.currentThread().interrupted(). Это правильный способ его использования, или это Thread.interrupted() достаточно?

4 ответов


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

сначала необходимо определить, проверяет ли код состояние прерывания (или обрабатывает InterruptedException) считается "владельцем" потока. Если это так, в некоторых ограниченных случаях может быть уместно проглотить (или просто не бросить) InterruptedException а также прерванный статус, потому что владелец реализует политику отмены потока (Goetz,параллелизм Java на практике, p. 143).

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

  • оставьте состояние прерывания потока очищенным, но бросьте InterruptedException. (Это Thread.sleep() делает.)
  • сохранить статус прерывания.

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

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

if (Thread.currentThread().isInterrupted()) doSomething;

чем

if (Thread.interrupted()) {
    Thread.currentThread().interrupt();
    doSomething;
}

кроме того, как и в вашем первоначальном вопросе, если вы использовали Thread.interrupted() в условии while цикл, после того, как цикл ломается, вы не знаете, был ли он завершен, потому что Thread.interrupted() вернулся true или изменилось какое-то другое условие или break инструкция. Поэтому в этом случае используйте Thread.currentThread().isInterrupted() на самом деле только. (Конечно, вы может также кодировать цикл таким образом, что только причина выхода заключается в том, что поток прерывается, но тогда ваш код будет хрупким, потому что после цикла вы должны повторно прервать поток, и если кто-то позже пришел и изменил код, чтобы также вырваться из цикла по какой-то другой причине, вы будете прерывать поток, когда он изначально не был прерван.)

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

предупреждение: [статический] статический метод должен быть квалифицирован именем типа, потоком, а не выражением

некоторые другие инструменты могут делать то же самое, например Eclipse, который покажет:

статический метод interrupted() из потока типа должен быть доступен в статический способ


просто отвечая на последнюю часть вашего вопроса ...

Я тоже видел Thread.currentThread().interrupted(). Это правильный способ его использования, или это Thread.interrupted() достаточно?

в чисто функциональных терминах они означают одно и то же.

но с точки зрения читабельности,

    Thread.currentThread().interrupted()

делает посмотреть как вы вызываете метод экземпляра ... но это не так. Следовательно,

    Thread.interrupted()

лучше. И, конечно, Не делайте этого:

    Thread someThread = ...
    someThread.interrupted()

это выглядит так: вы будете тестировать someThread, а ты на самом деле тестирование текущего потока. Очень обманчиво!


разница очень тонкая и обычно не имеет значения. Вы можете, очевидно, установить или очистить прерванный флаг, как вы хотите. Нет даже стандартной практики, которая говорит: "используйте один и никогда не используйте другой".

главное-знать, что вы делаете с прерванным флагом: оставляя его в состоянии, которое вы специально не намеревались, определенно не сделайте только тонкую разницу.

никогда использовать Thread.currentThread().interrupted(). Это просто ввести в заблуждение, особенно если у вас someOtherThread.interrupted().


есть ли разница в использовании Thread.interrupted() (кроме этого прерванный флаг очищается при использовании interrupted())?

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

Что касается разницы между Thread.currentThread().interrupted() и Thread.interrupted(), нет функциональной разницы, но последний короче, поэтому используйте его.