JavaRush /Java блог /Random UA /Що таке Deadlock в Java?
Alexey Smirnov
29 рівень
Москва

Що таке Deadlock в Java?

Стаття з групи Random UA
Рівень знань, необхідних розуміння статті: ви пройшли квести Java Syntax і Java Core, і у процесі вивчення Java Multithreading. Deadlock або дідлок в Java або взаємне блокування - це помилка, яка відбувається, коли нитки мають циклічну залежність від пари синхронізованих об'єктів. Уявіть, що одна нитка входить до монітора об'єкта x, а інша – об'єкта y. Якщо нитка в об'єкті xнамагається викликати будь-який синхронізований метод об'єкта y, а об'єкт yодночасно намагається викликати будь-який синхронізований метод об'єкта x, то нитки застрянуть у процесі очікування. Що таке Deadlock?  - 1Нижче приклад з туторіалу java docs про таке поняття, як deadlock. Де тут відбувається блокування ниток?
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
Що таке Deadlock?  - 2
У цьому випадку обидві нитки заблоковані, і кожна очікує, що інша віддасть лок. Але жодна це не зробить, тому що для цього потрібно завершити свій метод, а він заблокований іншою ниткою. Тому вони застрягли на місці, трапився deadlock. Втім, можливе й інше переплетення, в якому одна з ниток встигне завершитися до початку другої:
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. Автор відповіді: Dave Lillethun
Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ