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

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

Рівень 6, Лекція 9
Відкрита

— Привіт, Аміго! Погодься, з цим 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 class Main {
    public static void main(String[] args) throws Exception {
        Clock clock = new Clock();
        Thread clockThread = new Thread(clock);
        clockThread.start();

        Thread.sleep(10000); // головний потік спить 10 секунд
        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) всі винятки, що виникли.

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

Коментарі
  • популярні
  • нові
  • старі
Щоб залишити коментар, потрібно ввійти в систему
Для цієї сторінки немає коментарів.