undefined

DeadLock, и его причины

Java Multithreading
7 уровень , 3 лекция
Доступна
DeadLock, и его причины - 1

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

Сегодня я тебе расскажу, что такое дедлок (DeadLock) — взаимная блокировка.

— Так ты же уже что-то такое рассказывала.

— Ага, было дело. Но сегодня мы рассмотрим эту тему детальнее.

В самом простом случае в дедлоке участвуют две нити и два объекта-мютекса. Взаимная блокировка возникает, когда:

А) Каждой нити в процессе работы нужно захватить оба мютекса.

Б) Первая нить захватила первый мютекс и ждет освобождения второго.

В) Вторая нить захватила второй мютекс и ждет освобождения первого.

Примеры:

Пример
 public class Student
{
 private ArrayList friends = new ArrayList();

 public synchronized ArrayList getFriends()
 {
  synchronized(friends)
  {
   return new ArrayList(friends);
  }
 }

 public synchronized int getFriendsCount()
 {
  return friends.size();
 }

 public int addFriend(Student student)
 {
  synchronized(friends)
  {
   friends.add(student)
   return getFriendsCount();
  }
 }
}

Допустим, первая нить вызвала метод getFriends, тогда она сначала захватит мютекс объекта this, а затем мютекс объекта friends.

Вторая нить при этом вызвала метод addFriend, она сначала захватывает мютекс объекта friends, а затем мютекс объекта this (при вызове getFriendsCount).

Сначала все будет хорошо, но как гласит Закон Мерфи — если неприятность может случиться, она случается. Обязательно возникнет ситуация, когда первая нить успеет захватить только один мютекс, а вторая нить в это время захватит второй. Они так и будут висеть вечно в ожидании, что кто-то из них первым освободит мютекс.

Еще один простой пример, нашла в книге:

Пример
class KnightUtil
{
 public static void kill(Knight knight1, Knight knight2)
 {
  synchronized(knight1)
  {
   synchronized(knight2)
   {
    knight2.live = 0;
    knight1.experience +=100;
   } 
  }
 }
}

Есть игра, где два рыцаря сражаются друг с другом. Один рыцарь убивает другого. Это поведение отражено в методе kill. Туда передаются два объекта-рыцаря.

Сначала мы защищаем оба объекта, чтобы никто больше не мог их изменить.

Второй рыцарь умирает (live=0)

Первый рыцарь получает +100 опыта.

Все вроде бы отлично, но иногда может возникнуть ситуация, когда второй рыцарь в это время атакует первого. Для него тоже вызывается этот метод, но рыцари передаются в другом порядке.

— Т.е. нам даже не нужно несколько методов для получения дедлока?

— Ага. Иногда бывает достаточно одного простого метода, в котором уже могут происходить процессы, приводящие к зависанию нитей и всей программы.

— Да, оказывается, это явление встречается чаще, чем я думал. Спасибо, Элли.

Комментарии (41)
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION
Игорь Уровень 34 Минск Беларусь
19 апреля 2021
Дедлок это когда ты ищешь работу на позицию Джуна, но тебя не берут, потому что нет опыта работы на реальном проекте
Даниил Александрович Уровень 35 Тамбов Россия
27 марта 2021
прищемило причиндал в лифте дверью и при этом отключили свет, это пожалуй забавный дедлок.
Павел Бойко Уровень 41 Россия
12 сентября 2020
"А теперь, уважаемые телезрители, посмотрим на пример дедлока в дикой природе"
Антон Уровень 35 Сочи Сочи
29 апреля 2020
А как нить может захватит мютекс второго рыцаря, не захватив мютекс первого? Ведь мютекс второго рыцаря, находится ВНУТРИ монитора с мютекса первого рыцаря.
Павел Уровень 29 Санкт-Петербург Россия Expert
8 ноября 2019
объясните пожалуйста второй пример, как конкретно заходят нити в эту двойную синхру
Konstantin Уровень 41 Одесса
5 августа 2019
Вот интересно, почему всегда вспоминают про deadlock, но никогда ещё о двух других случаях? ПРОБЛЕМА ЖИВУЧЕСТИ(liveness) потоков. 1. Deadlock(динамическая взаимоблокировка) Возникает в случае если поток х1 заблокировал ресурс у1 и хочет получить доступ к ресурсу у2. При этом существует поток х2, заблокировавший ресурс у2, и желающий получить доступ к ресурсу у1. Замечание: при запуске потоков может наступить не сразу, потоки некоторое время могут работать не мешая друг другу. 2. Livelock(динамическая самоблокировка?) Поток пытается совершить действие, которое постоянно проваливается. В итоге действие повторяется снова и снова. 3. Starvation(неопределённая отсрочка) Ситуация связана с планировщиком ОС и приоритетами выполняемых потоков. В ситуации когда в системе всегда есть потоки с высоким приоритетом, которым постоянно предоставляется доступ к ресурсам ОС, потоки с низким приоритетом могут находиться в состоянии постоянного ожидания.
Вадим Чубаров Уровень 28
15 февраля 2019
если отбросить все эти программерские понты , то можно привести простую аналогию : - если в палате есть только одни тапки , то кто первый встал того и тапки ... вопросов нет - если в палате двое пар тапок , а Вася и Петя встали первые и в спешке их обули , а потом поняли что одному они жмут , а другому большие , то им бы было неплохо поменяться , но они в ссоре и гордость не позволяет....так и ходят деадлоком ))
Andrii Gorshunov Уровень 41 Польша Expert
4 февраля 2019
Случай, когда произойдет dead-lock, это когда блокируются объекты в одном потоке(t1) в одном порядке, а в другом потоке(t2) - в другом порядке. Thread1 >> lock1, lock2 Thread2 >> lock2, lock1 Когда первый поток захватил lock1, а второй поток захватил lock2, то первый ждет пока освободится lock2, соответственной второй поток, ждет пока освободится lock1 Способы избежания dead-lock-а: 1.Забирать lock-и в одном и тоже порядке в разных потоках 2. Что если надо забирать локи в разных порядках, тогда пригодится Reentrant lock Можно написать метод и избежать deadlock...
RuslanN Уровень 35 Нижний Новгород Россия
28 января 2019
Зачем в синхронизированном методе писать синхронизированный блок? Для чего всинхронизироанном блоке писать ещё один синхронизированнный блок ?
Di Уровень 38 Москва Россия
8 января 2019
А в чем проблема в примере с рыцарями?