JavaRush /Java блог /Архив info.javarush /Что такое дедлок
lexmirnov
29 уровень
Москва

Что такое дедлок

Статья из группы Архив info.javarush
Перевод грамотного объяснения примера из javadocs со Stackoverflow public class Deadlock { static class Friend { private final String name; public Friend(String name) { this.name = name; } public String getName() { return this.name; } public synchronized void bow(Friend bower) { System.out.format("%s: %s" + " has bowed to me!%n", this.name, bower.getName()); bower.bowBack(this); } public synchronized void bowBack(Friend bower) { System.out.format("%s: %s" + " has bowed back to me!%n", this.name, bower.getName()); } } public static void main(String[] args) { final Friend alphonse = new Friend("Alphonse"); final Friend gaston = new Friend("Gaston"); new Thread(new Runnable() { @Override public void run() { // System.out.println("Thread 1"); alphonse.bow(gaston); // System.out.println("Th: gaston bowed to alphonse"); } }).start(); new Thread(new Runnable() { @Override public void run() { // System.out.println("Thread 2"); gaston.bow(alphonse); // System.out.println("2.gaston waiting alph bowed"); } }).start(); } } Здесь нужно понять две важные вещи: 1) Что делает каждая из одновременно выполняющихся нитей? 2) Какие локи используются? Начнем с конца. Вы создали два объекта класса Friend: alphonse и gaston. У каждого из них есть свой лок. Так что локов два: альфонсов и гастонов. При входе в синхронизированный метод объекта, лок этого объекта запирается, и освобождается - отпирается - когда из метода выходят. Теперь о нитях. Первая, назовем ее нить Alphonse (с большой буквы, чтобы отличить от объекта alphonse) делает следующее (A - обозначает Alphonse) A: alphonse.bow(gaston) - получает лок alphonse A: gaston.bowBack(alphonse) - получает лок gaston A: возвращается из обоих методов, тем самым освобождая лок В это самое время нить Gaston... G: gaston.bow(alphonse) - получает лок gaston G: alphonse.bowBack(gaston) - получает лок alphonse G: возвращается из обоих методов, тем самым освобождая лок Теперь сведем эти данные вместе и получим ответ. Нити могут переплетаться (т. е. их события совершаться) в разных порядках. Дедлок, к примеру, получится, если опрядок будет таким: A: alphonse.bow(gaston) - получает лок alphonse G: gaston.bow(alphonse) - получает лок gaston G: пытается вызвать alphonse.bowBack(gaston), но блокируется, ожидая лока alphonse A: пытается вызвать gaston.bowBack(alphonse), но блокируется, ожидая лока gaston В этом случае обе нити заблокированы и каждая ожидает, что другая отдаст лок. Но ни одна это не сделает, потому что для этого нужно завершить свой метод, а он заблокирован другой нитью. Поэтому они застряли на месте - дедлок. Впрочем, возможно и другое переплетение, в котором одна из нитей успеет завершиться до начала второй: A: alphonse.bow(gaston) - получает лок alphonse A: gaston.bowBack(alphonse) - получает лок gaston A: возвращается из обоих методов, открывая оба лока G: gaston.bow(alphonse) - получает лок gaston G: alphonse.bowBack(gaston) - получает лок alphonse G: возвращается из обоих методов, открывая оба лока В этом случае дедлока нет. Например, добавлен какой-то метод, позволяющий другой нити успеть выполниться. Когда результат зависит от порядка одновременно происходящих событий (запланированного порядка или скорости выполнения), это называется "race condition" - "состоянием гонки". Не все race condition потенциально производят дедлок, однако, по моему опыту, дедлоки происходят только в race condition.
Комментарии (1)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
partiec Уровень 33
21 июля 2023
спасибо 🙂🤘