Сначала объяснение:
Прерванный статус потока - это в основном логический флаг, который устанавливается в «true» с помощью interrupt()
.
Текущее состояние этого флага может быть читать с использованием Thread.currentThread().isInterrupted()
.
Если прерываемая операция (например, Object.wait()
или Thread.sleep()
) находит установленный флаг прерывания
он выбросит InterruptedException
и в то же время очистит (со значением «false») флаг, который может выглядеть следующим образом:
if ( Thread.interrupted() ) { throw new InterruptedException(); }
Обратите внимание и запомните, что Thread.interrupted()
неявно очищает прерванный флаг!
Это означает, что к тому времени, когда ваш catch( InterruptedException ie) {...}
будет выполнен,
Сам поток не знает, что он был прерван.
Тем не менее, давайте рассмотрим два примера:
Сначала пример задачи, которая поддерживает отмену.
Здесь нам не важно, как далеко продвигается задание до того, как его прервать:
public void run() {
int x = 0;
try {
while (x < 10) {
Thread.sleep(1000); // Some interruptible operation
x++;
}
System.out.println("x = " + x);
} catch (InterruptedException ie) {
System.out.println("Interrupted: x = " + x);
// We know we've been interrupted.
// Let the caller know it, too:
Thread.currentThread().interrupt();
}
}
Этот код пытается посчитать x от 0 до 10. Если он не прерван, он завершится и выдаст «x = 10».
Однако, если поток прерывается между ними, InterruptedException
будет выброшено, прерывая текущую задачу увеличения x.
В этом случае вывод может быть любым от «Прервано: x = 0» до «Прервано: x = 9», в зависимости от того, когда поток был прерван.
Обратите внимание, что считается хорошей практикой восстанавливать прерванный флаг потока перед выходом, так как
в противном случае прерванный статус не будет виден вызывающей стороне этого run()
метода.
Теперь, если крайне важно, чтобы наша задача выполнялась полностью, чтобы вывод всегда был "x = 10", что означает, что задача не поддерживает отмену, нам нужен другой подход:
public void run() {
int x = 0;
boolean wasInterrupted = false; // <- This is the local variable to store the interruption status
while (x < 10) {
wasInterrupted = wasInterrupted || Thread.interrupted(); // not really needed in this case, but for the sake of completeness...
try {
Thread.sleep(1000); // <- Some interruptible operation
} catch (InterruptedException e) {
wasInterrupted = true;
}
x++;
}
System.out.println("x = " + x);
if ( wasInterrupted ) {
Thread.currentThread().interrupt();
}
}
В этом случае мы продолжаем обработку даже после InterruptedException
, пока задача не будет завершена.
Чтобы быть хорошим, если мы обнаруживаем прерывание, мы сохраняем это условие в wasInterrupted
, чтобы мы могли
правильно установите флаг прерывания перед возвратом из метода.
Вот что означает
должен сохранить статус прерывания локально и восстановить его непосредственно перед возвратом.
Там написано «должен», потому что мы не обязаны строго обрабатывать прерывания - мы можем просто игнорировать любые InterruptedException
и просто завершить нашу задачу, а затем вернуться. Однако это не является хорошей практикой, упомянутой выше, и может вызвать проблемы в некоторых сценариях.