Часто можно встретить код, вроде такого:
Если не понимать логику работы прерываний, то напрашивается вопрос: для чего поток прерывает сам себя? На самом деле, выражение "прерывание потока" не очень удачное. Для этого есть устаревший(deprecated) и небезопасный метод stop, которым не рекомендуется пользоваться. Сам разработчик потока должен думать о корректном завершении работы своего потока.
Вызов метода потока interrupt просто устанавливает флаг, означающий, что код, использующий этот поток, хочет его прервать. Поток может узнать об этом желании вызовом isInterrupted, и решить, что ему делать дальше.
Часто хорошим решением в этой ситуации является генерация исключения InterruptedException. Посмотрим, например, на поведение Thread.sleep() – приостанавливает поведение потока, но проверяет флаг, и как только замечает, что он установлен, бросает InterruptedException.
Но разве недостаточно в catch-секции просто завершить работу потока? Это не очень хорошее решение, так как обработка исключения может происходить где-то глубоко на низком уровне, а поток должен совершить какую-нибудь работу перед завершением. А генерация исключения сбрасывает флаг, поэтому более высокоуровневые методы могут никогда не узнать о том, что поток был прерван, а следовательно и корректно завершить работу.
В следующем примере поток успешно поспит 2 раза, но третий сон будет прерван. Метод sleep2sec узнает об этом, но утаит эту информацию. Поэтому, поток будет выполнятся бесконечно, несмотря на проверку isInterrupted().
Тут есть 2 решения:
1. Пробросить исключение.
2. Снова установить флаг прерывания: Thread.currentThread().interrupt() в catch-секции, чтобы условие цикла выполнилось.
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
//Восстанавливаем статус прерывания потока
Thread.currentThread().interrupt();
}
Если не понимать логику работы прерываний, то напрашивается вопрос: для чего поток прерывает сам себя? На самом деле, выражение "прерывание потока" не очень удачное. Для этого есть устаревший(deprecated) и небезопасный метод stop, которым не рекомендуется пользоваться. Сам разработчик потока должен думать о корректном завершении работы своего потока.
Вызов метода потока interrupt просто устанавливает флаг, означающий, что код, использующий этот поток, хочет его прервать. Поток может узнать об этом желании вызовом isInterrupted, и решить, что ему делать дальше.
Часто хорошим решением в этой ситуации является генерация исключения InterruptedException. Посмотрим, например, на поведение Thread.sleep() – приостанавливает поведение потока, но проверяет флаг, и как только замечает, что он установлен, бросает InterruptedException.
Но разве недостаточно в catch-секции просто завершить работу потока? Это не очень хорошее решение, так как обработка исключения может происходить где-то глубоко на низком уровне, а поток должен совершить какую-нибудь работу перед завершением. А генерация исключения сбрасывает флаг, поэтому более высокоуровневые методы могут никогда не узнать о том, что поток был прерван, а следовательно и корректно завершить работу.
В следующем примере поток успешно поспит 2 раза, но третий сон будет прерван. Метод sleep2sec узнает об этом, но утаит эту информацию. Поэтому, поток будет выполнятся бесконечно, несмотря на проверку isInterrupted().
public class CatLife{
final public static void main(String[]args) throws InterruptedException{
Thread cat = new Thread(new Cat());
cat.start();
Thread.sleep(5000);
cat.interrupt();
cat.join();
}
static class Cat implements Runnable{
@Override
public void run() {
while(!Thread.currentThread().isInterrupted()){
System.out.println("Сон начинается");
sleep2sec();
System.out.println("Сон закончился\n");
}
System.out.println("Завершение работы потока");
}
private void sleep2sec(){
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
System.out.println("Сон прерван");
}
}
}
}
Тут есть 2 решения:
1. Пробросить исключение.
2. Снова установить флаг прерывания: Thread.currentThread().interrupt() в catch-секции, чтобы условие цикла выполнилось.