Прерванное исключение против 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 цикл оборвется?


person Jim    schedule 19.02.2013    source источник
comment
См. Здесь: stackoverflow.com/ questions / 9901649 /   -  person David Lavender    schedule 19.02.2013
comment
И здесь: stackoverflow.com/questions/1024651/   -  person David Lavender    schedule 19.02.2013
comment
Вам следует прочитать Закон о саботажном дверном звонке.   -  person OldCurmudgeon    schedule 19.02.2013


Ответы (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 выполняется.

person Jean Logeart    schedule 19.02.2013
comment
+1: однако я предпочитаю перехватывать исключения внутри цикла, а затем явно прерывать или продолжать. - person BigMike; 19.02.2013
comment
@BigMike Да, этот подход полностью соответствует максиме Java. Чем больше кода, тем лучше код. - person Marko Topolnik; 19.02.2013
comment
@MarkoTopolnik, просто я не хочу использовать блок catch для управления потоком моей программы, если мне нужно выйти из цикла, я хочу быть тем, кто заявляет об этом с явным разрывом, и это просто для кого завтра унаследую свой код ... - person BigMike; 19.02.2013
comment
@BigMike Другими словами, вы бы предпочли язык, в котором нет механизма исключений. Исключения контролируют поток, нравится вам это или нет; вы просто заставляете их управлять потоком таким образом, чтобы задействовать больше кода. - person Marko Topolnik; 19.02.2013
comment
@MarkoTopolnik, может быть, ты прав, я думаю, как обычно, это зависит от личного вкуса и сценария. Кстати, я честно ненавижу java, все еще люблю старый добрый C;) - person BigMike; 19.02.2013
comment
@BigMike Исключения также часто являются благом - что, если сигнал прерывания должен вырваться из 10-уровневого глубокого стека вызовов? Вам потребуется много стандартного кода, чтобы справиться с этим без исключений, и конечный результат никоим образом не будет более понятным или поддерживаемым. - person Marko Topolnik; 19.02.2013
comment
@Vakimshaar: Значит, во втором случае я должен сделать: Thread.currentThread.interrupt(), чтобы при возврате callMethod() цикл while прервался? - person Jim; 19.02.2013
comment
@Jim Во втором случае вы должны разместить блок try - catch вокруг callMethod() - person Jean Logeart; 19.02.2013
comment
@Vakimshaar: Почему? Если я сделаю try-catch внутри callMethod(), а в catch я сделаю Thread.currentThread.interrupt(), не разорвется ли цикл? - person Jim; 20.02.2013

Thread.sleep() очистит "состояние прерывания" перед выбросом InterruptedException. Вам нужно вызвать Thread.currentThread().interrupt() в блоке catch, иначе условие while, скорее всего, не будет успешным, потому что поток всегда будет «не прерываться» при возврате callMethod.

Исключение вызвано не методом interrupt(), а sleep() блокировкой потока, о котором было сообщено как о «прерванном». Более подробно это объясняется здесь. См. Также этот ответ.

person Javier    schedule 19.02.2013

Вызов прерывания в потоке сам по себе не вызывает исключения. Спящий режим или ожидание, пока установлен флаг прерывания, - это то, что вызывает 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(); 
}

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

person Nathan Hughes    schedule 24.08.2015