Прерванная исключительная ситуация против isInterrupted в цикле while
Предположим, что у меня есть следующий код:
while(!Thread.currentThread().isInterrupted()){
//do something
Thread.sleep(5000);
}
Сейчас Thread.sleep
генерирует InterruptedException, поэтому должно быть так:
while(!Thread.currentThread().isInterrupted()){
//do something
try{
Thread.sleep(5000);
} catch(InterruptedException e){
}
}
Если я ударил catch
будет ли while
цикл продолжить или мне нужно сделать Thread.currentThread().interrupt()
? Если я вызову этот метод, не вызовет ли это InterruptedException
? Иначе как я получил исключение в первую очередь?
Также если у меня есть:
while (!Thread.currentThread().isInterrupted()){
//do something
callMethod();
}
private void callMethod(){
//do something
try {
Thread.sleep(5000);
} catch(InterruptedException e){
}
}
опять будет мой while
разрыв цикла?
3 ответа
На самом деле ваш вопрос больше о try - catch - finally
чем о многопоточности.
1) Если sleep
бросает Exception
, catch
блок будет выполняться, а затем while
цикл продолжается.
2) Вы делаете то же самое, что и в 1)
Оставить while
цикл, сделать:
try{
while(!Thread.currentThread.isInterrupted){
//do something
Thread.sleep(5000);
}
}
catch(InterruptedException e){
}
В этом случае, если Exception
брошен, то while
цикл оставлен и catch
блок выполнен.
Вызов прерывания в потоке сам по себе не вызывает исключения. Спящий режим или ожидание, пока установлен флаг прерывания, является причиной возникновения исключения InterruptedException.
Совершенно предсказуемо, что может вызвать InterruptedException, так что прерываемый поток имеет контроль и может выбирать, как реагировать. Это проверенное исключение, поэтому очевидно, что его вызывает. Это не как ThreadDeath, который может быть брошен куда угодно.
При возникновении InterruptedException статус прерывания потока сбрасывается. Если вы хотите восстановить статус прерванного потока, потому что вы хотите проверить флаг позже и сделать его истинным, вызовите Thread.currentThread().interrupt()
для того, чтобы установить его.
Во время прерывания не происходит ничего необычного, чтобы изменить способ обработки инструкций. Поэтому, если вы решите перехватить InterruptedException в цикле и проверить флаг, чтобы выйти, вам нужно будет сбросить флаг:
while(!Thread.currentThread().isInterrupted()){
//do something
try{
Thread.sleep(5000);
} catch(InterruptedException e){
Thread.currentThread().interrupt();
}
}
В качестве альтернативы вы можете использовать InterruptedException, чтобы выйти из цикла:
try {
while (!Thread.currentThread().isInterrupted()) {
// do something
Thread.sleep(5000);
}
} catch (InterruptedException e) {
// flag value is not used here, but still good style
Thread.currentThread().interrupt();
}
Если этот последний фрагмент является целым методом выполнения прерывания потока, вы можете обойтись без повторной установки статуса прерывания, но если у вас есть компоненты, используемые другими частями, вы не хотите, чтобы одна деталь с плохим поведением подавляла прерванный поток. флаг, чтобы другой код в потоке не знал о прерывании.
Thread.sleep()
очистит "прерванный статус" перед броском InterruptedException
, Вам нужно позвонить Thread.currentThread().interrupt()
в блоке catch, в противном случае условие while, скорее всего, не будет выполнено, поскольку поток всегда будет "не прерываться", когда callMethod
возвращается.
Исключение не вызвано interrupt()
метод, но по sleep()
блокировка потока, который был сигнализирован как "прерванный". Это объясняется более подробно здесь. Смотрите также этот ответ.