Зачем вызывать Thread.currentThread.interrupt() в блоке перехвата InterruptException?
Зачем вызывать метод Thread.currentThread.interrupt() в блоке catch?
4 ответа
Это сделано, чтобы сохранить состояние.
Когда вы ловите InterruptException
и проглотив его, вы по существу не позволяете каким-либо высокоуровневым методам / группам потоков замечать прерывание. Что может вызвать проблемы.
По телефону Thread.currentThread().interrupt()
Вы устанавливаете флаг прерывания потока, так что обработчики прерываний более высокого уровня заметят это и могут обработать это соответствующим образом.
Java Concurrency на практике обсуждает это более подробно в главе 7.1.3: Реагирование на прерывание. Его правило таково:
Только код, который реализует политику прерывания потока, может проглотить запрос прерывания. Универсальный код задачи и библиотеки никогда не должен поглощать запросы прерывания.
Я думаю, что этот пример кода проясняет ситуацию. Класс, который делает работу:
public class InterruptedSleepingThread extends Thread {
@Override
public void run() {
doAPseudoHeavyWeightJob();
}
private void doAPseudoHeavyWeightJob() {
for (int i=0;i<Integer.MAX_VALUE;i++) {
//You are kidding me
System.out.println(i + " " + i*2);
//Let me sleep <evil grin>
if(Thread.currentThread().isInterrupted()) {
System.out.println("Thread interrupted\n Exiting...");
break;
}else {
sleepBabySleep();
}
}
}
/**
*
*/
protected void sleepBabySleep() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
//e.printStackTrace();
Thread.currentThread().interrupt();
}
}
}
Основной класс:
public class InterruptedSleepingThreadMain {
/**
* @param args
* @throws InterruptedException
*/
public static void main(String[] args) throws InterruptedException {
InterruptedSleepingThread thread = new InterruptedSleepingThread();
thread.start();
//Giving 10 seconds to finish the job.
Thread.sleep(10000);
//Let me interrupt
thread.interrupt();
}
}
Попробуйте вызвать прерывание без возврата статуса.
Замечания:
Как мне остановить поток, который ждет в течение длительного времени (например, для ввода)?
Чтобы этот метод работал, очень важно, чтобы любой метод, который перехватывает исключение прерывания и не был готов к его обработке, немедленно переустанавливал исключение. Мы говорим, скорее, подтверждает, а не отбрасывает, потому что не всегда возможно отбросить исключение. Если метод, который перехватывает InterruptedException, не объявлен для генерирования этого (проверенного) исключения, то он должен "сам себя прервать" следующим заклинанием:
Thread.currentThread().interrupt();
Это гарантирует, что Поток повторно вызовет InterruptedException, как только сможет.
Я бы посчитал это плохой практикой или хотя бы немного рискованной. Обычно методы более высокого уровня не выполняют блокирующих операций и никогда не увидят InterruptedException
там. Если вы маскируете его в каждом месте, где выполняете прерываемую операцию, вы никогда не получите его.
Единственное обоснование для Thread.currentThread.interrupt()
и не вызывать никакое другое исключение или сигнализировать запрос прерывания любым другим способом (например, установка interrupted
переменная локальной переменной в главном цикле потока) - это ситуация, когда вы действительно ничего не можете сделать с исключением, как в finally
блоки.
См. Ответ Петера Тёрока, если вы хотите лучше понять последствия Thread.currentThread.interrupt()
вызов.
Обратитесь к java doc
Если этот поток заблокирован при вызове функций wait(), join(), sleep(long), то его статус прерывания будет очищен, и он получит InterruptedException.
Если этот поток заблокирован в операции ввода-вывода, будет установлено состояние прерывания потока, и поток получит исключение ClosedByInterruptException.
Если этот поток заблокирован в селекторе, то будет установлен статус прерывания потока, и он немедленно вернется из операции выбора.
Если ни одно из предыдущих условий не выполняется, устанавливается состояние прерывания этого потока.
Итак, если вы измените метод sleepBabySleep() в ответе @Ajay George на операцию ввода-вывода или просто в sysout, вам не нужно возвращать статус, чтобы остановить программу. (Кстати, они даже не бросают InterruptedException)
Как сказал @Péter Török => Это сделано для сохранения состояния. (И особенно для метода, который генерирует InterruptedException)