undefined

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

Java Core
6 уровень , 9 лекция
Открыта

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

— Ага.

— На самом деле нечто подобное существует в классе Thread. Только переменная называется не isCancel, а isInterrupt, и метод остановки, соответственно, не 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();
   }
   System.out.println("Tik");
  }
 }
}
Т.к. много нитей могут вызвать метод run одного объекта, то объект Clock в своем методе run получает объект вызвавшей его нити («текущей нити»).

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

Когда переменная isInterrupt станет равной 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, есть автоматическая проверка переменной isInterrupt. Если нить вызовет метод sleep, то этот метод сначала проверит, а не установлена ли для текущей (вызвавшей его нити) переменная isInterrupt в true. И если установлена, то метод не будет спать, а выкинет исключение InterruptedException.

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

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

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

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

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

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

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

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

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

Комментарии (205)
Чтобы просмотреть все комментарии или оставить свой,
перейдите в полную версию
Error 404 17 уровень, Краснодар
22 апреля 2021
Не вкуривается эта лекция никак, прошлая зашла легко. Будем искать доп. материалы((
MTVen 22 уровень
27 марта 2021
Можно будет добавить табуляции в примерах? Не очень читабельная запись
Артем 41 уровень, Краснодар Master
19 февраля 2021
Когда переменная isInterrupt станет равной true, метод run завершится. не завершится) так как выбрасывание исключения, сбрасывает флаг обратно в false

     * @throws  InterruptedException
     *          if any thread has interrupted the current thread. The
     *          interrupted status of the current thread is
     *          cleared when this exception is thrown.
🦔 Виктор 20 уровень, Москва Expert
16 января 2021
Вместо тысячи слов: Всё получится!
Айбек 22 уровень, Бишкек
29 декабря 2020
Данный вариант прерывания потока расказывается на уроках Алишева. Для себя записал чтобы не забыть. если кто поймет мою запись то пожалуйста
Ilya 22 уровень, Санкт-Петербург
18 декабря 2020
Есть ощущение, что объяснено не очень очевидно, пришлось искать дополнительные источники) И вот что мне стало понятно, метод interrupt() не обязывает никого ничего останавливать, он просто информирует поток, типа тебя хотят остановить, а вот автору кода надо уже решить, брать во внимание это желание другого потока или нет, для остановки потока есть метод isInterrupted(), это марке, который говорит, пытается или нет кто-то остановить наш поток(true or false),добавляем его в while и вот если другие потоки не против мы работаем, если против останавливаем. Исключение на sleep, нужно как раз для того чтоб во время сна тоже можно было остановить спящий поток. Надеюсь кому то станет, как и мне, понятнее)
Igor 17 уровень, Edmonton
15 ноября 2020
Может кому-нибудь будет интересно знать, я потратил несколько часов на это :) Переменная isInterrupt на которую ссылается лекция, на самом деле лишь флаг. Корни этого флага закопаны глубоко и связаны между собой в JDK и JVM. Кому интересно посмотрите оригинальный код класса Thread.java и конкретно метода interrupt() - там очень интересно и местами пока вообще непонятно :) Как я понял нужно просто понимать что есть The Interrupt Status Flag https://docs.oracle.com/javase/tutorial/essential/concurrency/interrupt.html Все три метода: interrupt(), interrupted(), isInterrupted(), они работают не прямо с boolean переменной, а именно с этим внутренним флагом.
Regina Kazan 35 уровень, Казань
10 ноября 2020
Остановить бушующий поток : конспирологическая версия - пицца хат и младенцы...
Pig Man 41 уровень
27 октября 2020
У объектов типа Thread есть логическое поле/флаг со значением false по умолчанию. ОбъектПотока.interrupt() - просто меняет этот флаг на true, чтобы условие цикла

while (!current.isInterrupted()) {}
стало ложным и он оборвался. .isInterrupted() как раз возвращает значение флага. Проблема в том, что при использовании статического метода класса Thread - Thread.sleep(10000) и ОбъектПотока.join() программа "засыпает", и следовательно, никаких проверок условия while не происходит. Короче говоря, если поток заснет на 100 лет, а мы его прервем, то узнает он об этом лишь по прошествии этих 100 лет, так как условия выхода из цикла никто не проверял все это время. Именно поэтому метод join и sleep постоянно проверяют, не был ли изменен флаг текущего потока, и если был, то нафиг ждать 100 лет, выбрасываем InterruptedException и поехали дальше. Поэтому: " Более того, в методе sleep, который так любят использовать для организации вечного цикла в методе run, есть автоматическая проверка переменной isInterrupt. Если нить вызовет метод sleep, то этот метод сначала проверит, а не установлена ли для текущей (вызвавшей его нити) переменная isInterrupt в true. И если установлена, то метод не будет спать, а выкинет исключение InterruptedException. "
ERGAN 22 уровень
26 октября 2020
Жесть. Вот по этой лекции вообще ничего не понятно. И пример конечно хуже некуда.