27 Соб.1 Что такое дедлок? Какие вы знаете стратегии, предотвращающие появление дедлоков? Могут ли возникнуть дедлоки при использовании методов wait-notify? Что чаще используется: notify или notifyAll? Метод wait рекомендуется использовать с конструкциями if или while?

  

27.1   Що таке дедлок?

 Дедлок (англ.. deadlock) - взаємне блокування – ситуація, при якій два чи більше програмних потоків не можуть продовжити роботу, так як знаходяться в стані очікування ресурсів, зайнятих один одним, і жоден з них не може продовжити роботу.

Н-д: Є дві нитки (thread), кожній нитці потрібно захопити два мютекси -> перша нитка захопила перший мютекс -> друга нитка захопила другий мютекс -> перша впоралась з роботою, чекає звільнення другого мютексу (у другому ще виконує дії друга нитка) -> друга нитка виконала дії, чекає звільнення першого мютексу (перший зайнятий першою ниткою, яка очікує).  

Н-д: менеджер зробив термінове замовлення у постійного постачальника, який працює по передоплаті, керівник забороняє оплачувати рахунок поки не буде прийнятий товар. Нитка бухгалтер взяла рахунок -нитка постачальник оформила замовлення -> нитка бухгалтер очікує підтвердження прийняття товару, щоб оплатити рахунок -> нитка постачальник чекає оплати, щоб відправити товар.

 

27.2 Які Ви знаєте стратегії, що запобігають виникнення дедлоку?

Найкраща стратегія – продумана архітектура і набір правил, коли можна використовувати захоплення мютексів і в якому порядку.

 

Обробку та поводження із ситуаціями взаємного блокування можна умовно поділити на:

1.       Нехтування проблемою взагалі (т. з. «страусиний алгоритм»).

2.       Виявлення та відновлення. Дозволити відбутися взаємному блокуванню, виявити його, та виконати деякі дії.

3.       Динамічне уникнення взаємного блокування шляхом правильного розподілу ресурсів.

4.       Запобігання шляхом невиконання однієї із чотирьох умов виникнення взаємного блокування.

4.1. Умова взаємного виключення повинна виконуватись для нероздільних ресурсів. В загальному випадку, умову взаємного виключення неможливо обійти, оскільки деякі з ресурсів мають використовуватись лише в екслюзивному режимі.

4.2 Умова утримання та очікування - кожен раз, коли процес потребує нові ресурси, він повинен не утримувати інші ресурси. Можливі такі алгоритми:

- отримувати всі ресурси на початку роботи процесу до виконання решти операцій.

- отримувати новий ресурс лише за умови вивільнення зайнятих ресурсів. Перед запитом нового ресурсу, процес звільняє зайняті ним ресурси.

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

4.3 Умова примусового звільнення ресурсів:

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

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

4.4 Циклічне очікування. Уникнення циклічного очікування досягається встановленням порядку отримання доступу до ресурсів різних типів.

 

 

27.3 Чи можуть виникати дедлоки при використанні методів wait-notify?

Так, можуть. Умовно – перша нитка може чекати , щоб  її  вивела зі стану очікування друга нитка, яка, в свою чергу, чекає поки її  виведе зі стану очікування перша нитка.

 

 

27.4 Що частіше використовується: notify чи notifyAll?

Якщо декілька ниток очікують зняття блокування  певного обєкту, то метод

notify() – відправляє сповіщення тільки одній нитці, що очікує;

notifyAll() – відправляє сповіщення всім ниткам, які очікують зняття блокування.

 

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

Недолік  notifyAll() в тому, що він використовує більше ресурсів ЦП, ніж notify(). Але для впевненості, що сповіщення не буде витрачено впусту, краще використовувати  notifyAll().

 

 

27.5  Метод wait() рекомендовано використовувати з конструкціями if чи while?

(Метод wait() класу java.lang.Object переводить програмний потік, який його викликає, у стан очікування. Цим самим забезпечує звільнення монітора, який має доступ до ресурсу, використовуваного  іншими потоками.)

wait() рекомендовано використовувати у циклі while для забезпечення надійності: якщо нитку запустили помилково – цикл ще раз перевірить умову і, якщо потрібно чекатиме далі. Окрім того існує вірогідність виходу із стану очікування без виклику notify()/notifyAll().

 


Коментарі

Популярні дописи з цього блогу

27 Гугл 1 goto. Зарезервовані (ключові) слова. wait не в блоці synchronized. happens-before. BlockingQueue. Методи BlockingQueue

28. Соб 1. Какие приоритеты нитей бывают? Можно ли остановить нить, снизив ее приоритет до 0? Зачем нужен класс ThreadGroup? В какой группе нитей состоит main-thread? Что такое паттерн ThreadPool?

27. Соб.2 Что происходит после вызова метода notifyAll? Какие выгоды получает объект, если он immutable? Что такое «thread-safe»? Что такое «happens-before»? Что такое JMM? Какое исключение вылетит, если вызвать wait не в блоке synchronized?