JavaRush /Курси /Модуль 2. Java Core /Зупиніть бурхливий потік: офіційна версія

Зупиніть бурхливий потік: офіційна версія

Модуль 2. Java Core
Рівень 11 , Лекція 4
Відкрита

— Привіт, Аміго! Погодься, з цим 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) всі винятки, що виникли.

Ніхто не гарантує, що потік можна зупинити. Він може зупинитися лише сам.

Коментарі (2)
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ
Кирило Рівень 43
25 листопада 2024
В задачі 2 поламані тести
Сергій Рівень 44
8 червня 2025
Та ні, працює