JavaRush/Курсы/Java Core/Остановить бушующий поток: официальная версия

Остановить бушующий поток: официальная версия

Открыта

— Привет, Амиго! Согласись, Элли хорошо придумала с этим Cancel?

— Ага.

— На самом деле нечто подобное существует в классе Thread. Только переменная называется не isCancel, а isInterrupted, и метод остановки, соответственно, не cancel(), а interrupt().

— Да?

— Ага. Вот смотри:

Код Описание
class Clock implements Runnable
    public void run()
        Thread current = Thread.currentThread();


        while (!current.isInterrupted())
            try
                Thread.sleep(1000);
            } catch (InterruptedException e)
                e.printStackTrace();
                current.interrupt();
            }
            System.out.println("Tik");
        }
    }
}
Т.к. много нитей могут вызвать метод run одного объекта, то объект Clock в своем методе run получает объект вызвавшей его нити («текущей нити»).

Класс Clock (часы) будет писать в консоль раз в секунду слово «Tik», пока переменная isInterrupted текущей нити равна false.

Когда переменная isInterrupted станет равной true, метод run завершится.

public static void main(String[] args) throws Exception {
    Clock clock = new Clock();
    Thread clockThread = new Thread(clock);
    clockThread.start();


    Thread.sleep(10000);
    clockThread.interrupt();
}
Главная нить, запускает дочернюю нить – часы, которая должна работать вечно.

Ждет 10 секунд и отменяет задание, вызовом метода interrupt.

Главная нить завершает свою работу.

Нить часов завершает свою работу.

Более того, в методе sleep, который так любят использовать для организации вечного цикла в методе run, есть автоматическая проверка переменной isInterrupted. Если нить вызовет метод sleep, то этот метод сначала проверит, а не установлена ли для текущей (вызвавшей его нити) переменная isInterrupted в true. И если установлена, то метод не будет спать, а выкинет исключение InterruptedException.

— А зачем выкидывать исключение? Не лучше ли тоже просто в цикле вместо isCancel подставить isInterrupted()?

— Во-первых, не всегда в методе run есть цикл. Метод может состоять просто из двух десятков вызовов других методов. Тогда перед вызовом каждого придется добавлять проверку isInterrupted.

Во-вторых, вдруг какой-то метод очень долго исполняется, т.к. делает много разных действий.

В-третьих, выкидывание исключения – это не замена проверке isInterrupted, а скорее удобное дополнение. Выкинутое исключение позволяет быстро раскрутить стек вызовов до самого run.

В-четвертых, метод sleep часто используют, и, получается, к такому полезному методу неявно добавили не менее полезную проверку. Вроде бы никто специально проверку не добавлял, а она есть. Это очень ценно, когда ты используешь много чужого кода и не можешь сам добавить в него проверку.

В-пятых, дополнительная проверка не приводит к снижению производительности. Вызов метода sleep значит, что нить должна ничего не делать (спать), поэтому дополнительная работа никому не мешает.

— Серьёзные аргументы.

— И, наконец, последнее: ты можешь в своем методе run вызывать чужой код, к которому у тебя нет доступа (исходников и/или прав их менять). Он может не иметь проверок на isInterrupted, а также перехватывать с помощью try…catch(Exception e) все возникшие исключения.

Никто не гарантирует, что нить можно остановить. Она может остановиться только сама.

Комментарии (320)
  • популярные
  • новые
  • старые
Для того, чтобы оставить комментарий Вы должны авторизоваться
Denis Nkn
Уровень 26
17 октября, 20:02
Так в цикле while переменная isInterrupted или метод isInterrupted()?
TimJohnzz
Уровень 22
29 сентября, 15:46
Для тупых(меня): Если во время выполнения кода в методе run нашего потока(thread, нить) мы вызовем метод interrupt(), то он не прервет наш поток, он просто сообщит JVM, что этот поток должен быть прерван. Поэтому мы должны сами поставить проверку в нашем run на то, вызывался ли interrupt или нет. 1)В цикле это легко, в самом условии проверяем (!Thread.currentThread().isInterrupted) 2)Когда поток находится в sleep(), а нам нужно его прервать, то JVM сама разбудит его и завершит, так как любой sleep() обрабатывается в try catch, и при прерывании потока и выбрасывании исключения, он и завершится(в блоке catch пишем break; и ОБЯЗАТЕЛЬНО возвращаем наш флажок методом .interrupt(), так как при выбрасывании исключения его состояние сбрасывается) 3)если же у нас нет ни цикла, ни sleep(), а огромный блок кода, то делаем ручные проверки через какое то расстояние в коде - if(Thread.currentThread.isInterrupted){... return; }
Grigoryvvv
Уровень 28
Expert
4 сентября, 21:50
05.09.2026 / 26 уровень
nastya_zhadan
Уровень 66
8 сентября 2025, 10:32
Копирую картинку из популярных комментов
Anonymous #3585174
Уровень 33
22 августа 2025, 07:40
Like
Сайфер
Уровень 51
29 июля 2025, 16:16
1) Метод sleep() ПОСТОЯННО проверяет был ли прерван поток, а не только вначале выполнения этого метода. 2) Метод sleep(), если был прерван поток, выбросит исключение Interrupted Exception. Это исключение, как только будет выброшено, сразу же установит флаг interrupted обратно на false. Поэтому нужно вызывать в блоке catch снова вызов метода interrupt(). Сам по себе, метод interrupt не выбрасывает исключений, он просто установит флаг interrupted в true. Затем дальше по циклу снова идет проверка условия, и вот здесь уже этот цикл прерывается. Я этого не понимал раньше, из-за этого куча проблем было с попыткой врубиться в потоки.
Den Winchester
Уровень 32
9 ноября 2025, 11:57
спасибо, очень помог
Ruslan Gabzalilov
Уровень 27
6 февраля, 04:10
Спасибо добрый человек)
Anonymous #463526
Уровень 7
18 апреля 2025, 13:18
опять форматирование портит все ((
public static void main(String[] args) throws Exception {
  Clock clock = new Clock();   Thread clockThread = new Thread(clock);   clockThread.start();

  Thread.sleep(10000);
  clockThread.interrupt();
}
Ромушка Роман
Уровень 32
20 октября 2024, 18:49
По поводу прерывания я понял, это не так сложно. Не понял лишь, как быть в итоге с длинными по времени операциями или блоком из вызовов, например, 10-ти функций?
{Java_Shark}
Уровень 36
14 октября 2024, 09:05
++
Alex
Уровень 1
Expert
10 октября 2024, 13:55
Вот как я понял продолжение))
public static void main(String[] args) throws Exception {
   Clock clock = new Clock();
   Thread clockThread = new Thread(clock);
   clockThread.start();
   Thread.sleep(10000);
}
clockThread.interrupt() устанавливает флаг прерывания у потока clockThread, что приводит к тому, что метод isInterrupted() вернет true в цикле while в методе run(). Поток clockThread получит сигнал о прерывании. Если этот поток находится в состоянии ожидания (например, исполняется метод Thread.sleep()), он выбросит InterruptedException. Внутри метода run() класса Clock выполнится блок catch и поток завершит свою работу, так как isInterrupted() вернет true.