— Привіт, Аміго!
Все нове – добре забуте старе. Сьогодні я розповідатиму про зупинку ниток. Сподіваюся, ти вже забув, як працює метод interrupt().
— Так, Еллі повністю забув.
— Чудово. Тоді нагадую.
У Java, якщо хтось хоче зупинити нитку, що працює, у нього є можливість подати нитки про це сигнал. Для цього потрібно встановити приховану змінну нитки isInterrupted в true.
У кожної нитки (клас Thread) є метод interrupt(), який використовується для встановлення такого прапора. При виклику методуinterrupt() змінна isInterrupted всередині нитки встановлюється рівною true.
І коли нитка викликає методи Thread.sleep() або метод join(), у цих методах відбувається прихована перевірка – а чи не виставлений у нашої поточної нитки прапор isInterrupted. Якщо цей прапор виставлений (змінна isInterrupted рівно true), то методи викидають виняток InterruptedException.
Ось, нагадаю тобі старий приклад:
Код | Опис |
---|---|
|
Об'єкт Clock у своєму методі run отримує об'єкт поточної нитки.
Клас Clock (годинник) писатиме в консоль раз на секунду слово «Tik», поки змінна isInterrupt поточної нитки дорівнює false. Коли змінна isInterrupt стане рівною true, метод run завершиться. |
|
Головна нитка, запускає дочірню нитку – годинник, який повинен працювати вічно.
Чекає 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 не захопить його і не забуде про нього. Отже, жодних гарантій зупинки нитки немає.
Інша річ, що нитки вже вважають досить низькорівневим програмуванням. Але про це я розповім тобі наступного разу.
— Прямо не Еллі, а Шахеризада!
— Так, Аміго! Все зрозуміло з поточної лекції?
— Ага.
— Ось і добре.
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ