— Привіт, Аміго!

Все нове – добре забуте старе. Сьогодні я розповідатиму про зупинку ниток. Сподіваюся, ти вже забув, як працює метод interrupt().

— Так, Еллі повністю забув.

— Чудово. Тоді нагадую.

У Java, якщо хтось хоче зупинити нитку, що працює, у нього є можливість подати нитки про це сигнал. Для цього потрібно встановити приховану змінну нитки isInterrupted в true.

У кожної нитки (клас Thread) є метод interrupt(), який використовується для встановлення такого прапора. При виклику методуinterrupt() змінна isInterrupted всередині нитки встановлюється рівною true.

І коли нитка викликає методи Thread.sleep() або метод join(), у цих методах відбувається прихована перевірка – а чи не виставлений у нашої поточної нитки прапор isInterrupted. Якщо цей прапор виставлений (змінна isInterrupted рівно true), то методи викидають виняток InterruptedException.

Ось, нагадаю тобі старий приклад:

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

while(!current.isInterrupted())
{
Thread.sleep(1000);
System.out.println("Tik");
}
}
}
Об'єкт Clock у своєму методі run отримує об'єкт поточної нитки.

Клас Clock (годинник) писатиме в консоль раз на секунду слово «Tik», поки змінна isInterrupt поточної нитки дорівнює false.

Коли змінна isInterrupt стане рівною true, метод run завершиться.

public static void main(String[] args)
{
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.

— Але в цьому прикладі ми постійно перевіряємо змінну isinterrupted в умовах циклу.

Я пам'ятаю, були якісь причини, через які ми не могли використовувати такий підхід. Чи не нагадаєш?

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

По-друге, як якийсь метод дуже довго виконується, т.к. робить багато різних дій.

По-третє, викидання виключення – це не заміна перевірки перевіреного, а скоріше зручне доповнення. Викинутий виняток дозволяє швидко розкрутити стек викликів до самого run.

По-четверте, метод sleep часто використовують, і, виходить, до такого корисного методу неявно додали не менш корисну перевірку. Ніби ніхто спеціально перевірку не додавав, а вона є. Це дуже цінно, коли ти використовуєш багато чужого коду і не можеш сам додати до нього перевірку.

П'яте, додаткова перевірка не призводить до зниження продуктивності. Виклик методу sleep означає, що нитка не повинна нічого (спати), тому додаткова робота нікому не заважає.

— Справді, саме це ти й казала тоді.

А що щодо твоєї фрази «Ніхто не гарантує, що нитку можна зупинити. Вона може зупинитися лише сама». Чи можеш її розтлумачити?

— Звичайно.

Раніше, у перших версіях Java, у ниток був метод stop(). І за його виклику Java-машина справді зупиняла нитку. Але потім виявилося, що якщо нитка, яку переривали таким чином, робила щось за межами Java-машини і (наприклад, писала у файл або викликала функції ОС), то переривання такої нитки призводило до великої кількості проблем – незакриті файли, незвільнені зайняті системні ресурси тощо

На спільній нараді проектувальників Java було вирішено прибрати метод примусової зупинки ниток. Тепер ми лише можемо встановити певний прапор (isinterrupted) і сподіватися, що код нитки був написаний правильно, і цей прапор буде оброблено. Цей прапор – це як плакат із написом – «нитка, зупинись, будь ласка, дуже треба!». Але вона зупиниться чи ні – це її справа.

— А як же InterruptedException?

— А якщо всередині коду, який працює в цій нитці, є купа try-catch блоків? Навіть якщо InterruptedException десь та й вискочить, абсолютно не факт, що якийсь try-catch не захопить його і не забуде про нього. Отже, жодних гарантій зупинки нитки немає.

Інша річ, що нитки вже вважають досить низькорівневим програмуванням. Але про це я розповім тобі наступного разу.

— Прямо не Еллі, а Шахеризада!

— Так, Аміго! Все зрозуміло з поточної лекції?

— Ага.

— Ось і добре.