
— Привет, Амиго!
Сегодня я тебе расскажу, что такое дедлок (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 опыта.
Все вроде бы отлично, но иногда может возникнуть ситуация, когда второй рыцарь в это время атакует первого. Для него тоже вызывается этот метод, но рыцари передаются в другом порядке.
— Т.е. нам даже не нужно несколько методов для получения дедлока?
— Ага. Иногда бывает достаточно одного простого метода, в котором уже могут происходить процессы, приводящие к зависанию нитей и всей программы.
— Да, оказывается, это явление встречается чаще, чем я думал. Спасибо, Элли.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ