Завершення роботи потоку

Робота потоку припиняється, коли відбувається вихід з його методу run Так відбувається нормальне завершення потоку, але ви можете зупинити потік і по-іншому

Бажано використовувати самий чистий спосіб, який, однак, вимагає деякої роботи з боку програміста: замість того щоб насильно припиняти існування потоку, краще дати йому завершитися добровільно Найчастіше для цього використовують логічну змінну, значення якої опитується потоком Наприклад:

Самий прямолінійний спосіб завершити потік – викликати його метод stop, який запустить обєкт ThreadDeath, вказавши йому в якості мети потрібний потік ThreadDeath є підкласом класу Error, а не Exception (Пояснення того, чому так було зроблено, наводиться в додатку Б) Програмістам не слід перехоплювати ThreadDeath, якщо тільки вони не повинні виконати які-небудь надзвичайно неординарні завершальні дії, з якими не впорається finally Якщо вже ви перехоплюєте ThreadDeath, обовязково збудіте обєкт-виняток заново, щоб потік міг померти. Якщо ж ThreadDeath НЕ перехоплюється, то обробник помилок верхнього рівня просто знищує потік, не вивільняючи ніяких повідомлень

Потік також може порушити ThreadDeath для самого себе, щоб завершити свою власну роботу Це може стати в нагоді, якщо потік заглибився на кілька рівнів нижче методу run і вам не вдається легко повідомити run про те, що пора закінчувати

Інший формі методу stop можна замість ThreadDeath передати якесь інше виняток Хоча зазвичай збудження винятків виявляється не найкращим способом для обміну інформацією між потоками, ви можете використовувати цю форму спілкування для того, щоб послати потоку якесь повідомлення Наприклад, якщо деякий потік виконує тривалі обчислення для певних вхідних значень, то інтерфейсний потік може дозволити користувачеві змінити ці значення прямо під час обчислень Звичайно, ви можете просто завершити потік і почати новий Проте, якщо проміжні результати обчислень можуть використовуватися повторно, то замість завершення потоку можна створити новий тип винятку Restart Calculation і скористатися методом stop, щоб запустити нове виключення в потік При цьому потік повинен перехопити виняток, розглянути нові вхідні значення, по можливості зберегти результати і відновити обчислення

Один потік може очікувати завершення іншого потоку Для цього застосовується один з методів join Найпростіша форма цього методу чекає завершення певного потоку:

class CalcThread extends Thread {

private double Result

public void run() {

Result = calculate()

}

public double result() {

return Result

}

public double calculate() {

// ..

}

}

class join {

public static void main(String[] args) { CalcThread calc = new CalcThread() calcstart()

doSomethingElse()

try {

calcjoin() Systemoutprintln(&quotresult is &quot

+ calcresult())

} catch (InterruptedException e) { Systemoutprintln(&quotNo answer: interrupted&quot)

}

}

}

Спочатку створюється новий тип потоку, CalcThread, що виконує деякі обчислення Ми запускаємо потік, деякий час займаємося іншими справами, після чого намагаємося приєднатися (join) до потоку На виході з join можна бути впевненим, що метод CalcThreadrun завершився, а значення Result отримано Це спрацює незалежно від того, закінчився чи потік CalcThread до doSomethingElse чи ні Коли потік завершується, його обєкт нікуди не зникає, так що ви можете до нього звертатися

При виклику інших форм join їм передаються інтервали тайм-ауту, подібні тим, які використовуються для методу sleep Є три форми join:

public final void join() throws InterruptedException

Чекає безумовного завершення потоку, для якого викликається метод public final synchronized void join(long millis)  throws       InterruptedException

Чекає завершення потоку або закінчення заданого числа мілісекунд (залежно від того, що станеться раніше) Аргумент, рівний нулю, означає очікування без тайм-

ауту

public final synchronized void join(long millis, int nanos)  throws       InterruptedException

Очікує завершення потоку або тайм-ауту з більш точним контролем часу Сумарний час тайм-ауту, рівне 0 наносекунд, знову означає очікування без тайм-ауту Кількість наносекунд знаходиться в діапазоні 0–999999

Виклик методу destroy для потоку – найрішучіша міра Цей метод знищує потік без виконання нормальних завершальних дій, до яких належить і зняття блокування з усіх обєктів потоку, так що застосування destroy може навічно заблокувати інші потоки По можливості намагайтеся уникати виклику destroy

910 Завершення додатки

Робота кожної програми починається з запуску одного потоку – того, в якому виконується метод main Якщо ваш додаток не створює інших потоків, то після виходу з main воно завершується Але давайте припустимо, що в додатку виникають інші потоки що станеться з ними після виходу з main

Існує два різновиди потоків: потоки-користувачі (users) і потоки-демони (daemons) Наявність залишилися потоків-користувачів призводить до продовження роботи програми, тоді як потоки-демони можуть знищуватися Після зняття останнього потоку-користувача відбувається закриття всіх потоків-демонів, і робота додатка

на цьому закінчується Для позначки потоку-демона застосовується метод setDaemon (true), а метод get Daemon перевіряє значення відповідного прапора За замовчуванням

“Демонічний статус потоку збігається зі статусом його потоку-творця Після того як потік почне виконуватися, змінити дане властивість неможливо при спробі зробити це збуджується виключення IllegalThreadState  Exception

Якщо новий потік породжується в методі main, то він успадковує від свого творця статус потоку-користувача Після завершення main додаток буде виконуватися до того,

як завершиться і цей породжений потік У вихідному потоці немає нічого особливого – просто він виявляється першим при конкретному запуску програми Після цього такий потік нічим не відрізняється від всіх інших потоків Додаток працює до тих пір, поки не будуть завершені всі його потоки-користувачі З точки зору runtime-системи, вихідний потік створюється лише для того, щоб породити інший потік і померти, надаючи породженому потоку виконувати всю роботу Якщо ви хочете, щоб ваш додаток завершувалося разом із завершенням вихідного потоку, необхідно позначати всі створювані потоки як потоки-демони

Джерело: Арнольд К, Гослінг Д – Мова програмування Java (1997)

Схожі статті:


Сподобалася стаття? Ви можете залишити відгук або підписатися на RSS , щоб автоматично отримувати інформацію про нові статтях.

Коментарів поки що немає.

Ваш отзыв

Поділ на параграфи відбувається автоматично, адреса електронної пошти ніколи не буде опублікований, допустимий HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

*