Взаємне блокування

Якщо ви маєте справу з двома потоками і з двома блокуємими обєктами, може виникнути ситуація взаємного блокування (deadlock), При якій кожен обєкт чекає зняття блокування з іншого обєкта Уявімо собі, що обєкт X містить синхронізований метод, усередині якого викликається синхронізований метод обєкту Y, який, у свою чергу, також містить синхронізований метод для виклику синхронізованого методу обєкта X Кожен обєкт чекає, поки з іншого обєкта не буде знято блокування, і в результаті ні один з них не працює Подібна ситуація іноді називається смертельними обіймами (deadly embrace) Розглянемо сценарій, відповідно до якого обєкти jareth і cory відносяться до деякого класу Friend ly:

1 Потік 1 викликає синхронізований метод jarethhug З цього моменту потік 1

здійснює блокування обєкта jareth

2 Потік 2 викликає синхронізований метод coryhug З цього моменту потік 2

здійснює блокування обєкта cory

3 Тепер coryhug викликає синхронізований метод jarethhugBack Потік 1 блокується, оскільки він очікує зняття блокування з cory (нині здійснюваної потоком 2)

4 Нарешті, jarethhug викликає синхронізований метод coryhugBack Потік 2 також блокується, оскільки він очікує зняття блокування з jareth (нині здійснюваної потоком 1)

Виникає взаємне блокування – cory не працює, поки не знято блокування з jareth, і навпаки, і два потоку навчань застрягли в безвиході

Звичайно, вам може пощастити, і один з потоків завершить весь метод hug без участі другого Якби етапи 3 і 4 слідували б в іншому порядку, то обєкт jareth виконав би hug і hugBack ще до того, як cory знадобилося б заблокувати jareth Однак у майбутніх запусках того ж додатка планувальник потоків міг би спрацювати інакше, приводячи до взаємної блокуванні Найпростіше рішення полягає в тому, щоб оголосити методи hug і hugBack несинхронізованих і синхронізувати їх роботу по одному обєкту, спільно використовуваному усіма обєктами Friendly Це означає, що в будь-який момент часу під всіх потоках може виконуватися рівно один метод hug – небезпека взаємного блокування при цьому зникає Завдяки іншим, більш хитромудрим прийомам вдається одночасно виконувати декілька hug без небезпеки взаємного блокування

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

97 Призупинення потоків

Потік може бути призупинений (suspended), Якщо необхідно бути впевненим у тому,

що він відновиться лише з вашого дозволу Для прикладу припустимо, що користувач натиснув кнопку C ANCEL під час виконання тривалої операції Роботу слід призупинити до того моменту, коли користувач підтвердить (або ні) своє рішення Фрагмент програми може виглядати наступним чином:

Thread spinner / / Потік, що виконує обробку

public void userHitCancel() {

spinnersuspend () / / Призупинення

if (askYesNo(&quotReally Cancel&quot))

spinnerstop () / / Припинення операції

else

}

spinnerresume () / / Передумав

Метод userHitCancel спочатку викликає suspend для потоку, що виконує операцію, щоб зупинити його аж до вашого розпорядження Потім користувач повинен відповісти, чи дійсно він хоче скасувати операцію Якщо так, то метод stop знімає потік в іншому випадку метод resume відновлює роботу потоку

Призупинення раніше зупиненого потоку, а також відновлення роботи потоку,

який не був припинений, не призводить ні до яких небажаних наслідків

98 Переривання потоку

У деяких методах класу Thread згадується переривання (interrupting) потоку Відповідні методи зарезервовані для можливості, яка незабаром буде включена в Java На момент написання цієї книги вони ще не повністю реалізовані спроба їх виклику призводить до порушення виключення NoSuchMethodError і знищенню викликає потоку Цілком можливо, що до того моменту, коли ви будете читати цю книгу, ці методи вже будуть реалізовані У даному розділі наводиться їх короткий огляд

Концепція переривання виявляється корисною, якщо виконуваного потоку необхідно надати деяку ступінь контролю над моментом обробки події Наприклад, в циклі виводу може знадобитися інформація з бази даних, яку видобувають

допомогою транзакції якщо при цьому надходить запит на припинення роботи,

бажано дочекатися нормального завершення транзакції Потік користувача інтерфейсу може реалізувати такий запит, перериваючи потік виводу і даючи йому можливість дочекатися кінця транзакції Подібна схема буде добре працювати лише в тому випадку, якщо потік виводу добре поводиться і в кінці кожної транзакції перевіряє, чи не чи надійшов запит на переривання (і припиняє роботу в цьому випадку)

Переривання потоку в загальному випадку не повинно впливати на його роботу, проте деякі методи (такі, як sleep або wait) збуджують виняток InterruptedException Якщо у вашому потоці під час переривання виконувався один з таких методів, то буде порушено переривання Interrupted Exception

Для роботи з перериваннями використовуються кілька методів Метод interrupt посилає переривання в потік метод isInterrupted перевіряє факт переривання потоку статичний метод interrupted перевіряє, переривався Чи поточний потік

Джерело: Арнольд К, Гослінг Д – Мова програмування 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>

*

*