Что такое deadlock (взаимная блокировка) и приведите пример на Java?

«Что такое deadlock (взаимная блокировка) и приведите пример на Java?» — вопрос из категории Java Core, который задают на 10% собеседований Java Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Deadlock (взаимная блокировка) — это ситуация в многопоточном программировании, когда два или более потока бесконечно ожидают друг друга, освобождения заблокированных ими ресурсов (мониторов объектов).

Классический пример из жизни: Два человека (Поток A и Поток B) стоят в дверном проеме. Каждый ждет, пока другой отступит, чтобы пройти первым. Никто не двигается — возникает тупик.

Технический пример на Java:

public class DeadlockExample {
    private static final Object lock1 = new Object();
    private static final Object lock2 = new Object();

    public static void main(String[] args) {
        Thread threadA = new Thread(() -> {
            synchronized (lock1) { // 1. threadA захватывает lock1
                System.out.println("Thread A: Holding lock 1...");
                try { Thread.sleep(100); } catch (InterruptedException e) {}
                System.out.println("Thread A: Waiting for lock 2...");
                synchronized (lock2) { // 3. threadA пытается захватить lock2, но он у threadB
                    System.out.println("Thread A: Acquired both locks!");
                }
            }
        });

        Thread threadB = new Thread(() -> {
            synchronized (lock2) { // 2. threadB захватывает lock2
                System.out.println("Thread B: Holding lock 2...");
                try { Thread.sleep(100); } catch (InterruptedException e) {}
                System.out.println("Thread B: Waiting for lock 1...");
                synchronized (lock1) { // 4. threadB пытается захватить lock1, но он у threadA
                    System.out.println("Thread B: Acquired both locks!");
                }
            }
        });

        threadA.start();
        threadB.start(); // Программа зависнет в deadlock
    }
}

Условия возникновения deadlock (Условия Коффмана):

  1. Взаимное исключение: Ресурс не может быть использован более чем одним потоком одновременно.
  2. Удержание и ожидание: Поток, удерживая один ресурс, ждет другой.
  3. Отсутствие вытеснения: Ресурс нельзя отнять у потока, только добровольно освободить.
  4. Циклическое ожидание: Возникает круг потоков, каждый из которых ждет ресурс, удерживаемый следующим в цепи.

Профилактика: Упорядочивание захвата блокировок, использование tryLock() с таймаутом, избегание вложенных синхронизаций.