Ответ
Взаимная блокировка (Deadlock) — это состояние в многопоточном программировании, при котором два или более потока бесконечно ожидают освобождения ресурсов, заблокированных друг другом, что приводит к полной остановке выполнения.
Условия возникновения (Куффман-Коффман):
- Взаимное исключение (Mutual Exclusion): Ресурс не может использоваться несколькими потоками одновременно.
- Удержание и ожидание (Hold and Wait): Поток удерживает один ресурс и ожидает другой.
- Отсутствие вытеснения (No Preemption): Ресурс нельзя отнять у потока, только добровольно освободить.
- Циклическое ожидание (Circular Wait): Возникает цикл потоков, где каждый ожидает ресурс, удерживаемый следующим.
Пример на 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 t1 = new Thread(() -> {
synchronized (lock1) {
System.out.println("Thread 1: Holding lock1...");
try { Thread.sleep(100); } catch (InterruptedException e) {}
System.out.println("Thread 1: Waiting for lock2...");
synchronized (lock2) { // Блокировка: lock2 удерживается t2
System.out.println("Thread 1: Acquired lock2!");
}
}
});
Thread t2 = new Thread(() -> {
synchronized (lock2) {
System.out.println("Thread 2: Holding lock2...");
try { Thread.sleep(100); } catch (InterruptedException e) {}
System.out.println("Thread 2: Waiting for lock1...");
synchronized (lock1) { // Блокировка: lock1 удерживается t1
System.out.println("Thread 2: Acquired lock1!");
}
}
});
t1.start();
t2.start(); // Потоки зависнут в deadlock.
}
}
Стратегии предотвращения:
- Упорядоченный захват ресурсов: Всегда захватывайте блокировки в строго одинаковом глобальном порядке (например, сначала
lock1, потомlock2). - Использование
tryLockс таймаутом: ВместоsynchronizedиспользуйтеReentrantLock.tryLock(long timeout, TimeUnit unit)из пакетаjava.util.concurrent.locks. - Сокращение области видимости блокировки: Удерживайте блокировки минимально необходимое время.
- Обнаружение и восстановление: Используйте мониторинг для выявления deadlock'ов (например, через
ThreadMXBean.findDeadlockedThreads()) и принудительного прерывания одного из потоков.