Ответ
Deadlock (взаимная блокировка) возникает при одновременном выполнении четырех условий (Условия Коффмана):
- Взаимное исключение (Mutual Exclusion): Ресурс не может быть использован более чем одним потоком одновременно.
- Удержание и ожидание (Hold and Wait): Поток, удерживая один ресурс, запрашивает другой.
- Отсутствие вытеснения (No Preemption): Ресурс может быть освобожден только потоком, который его удерживает.
- Циклическое ожидание (Circular Wait): Существует замкнутая цепь потоков, где каждый ждет ресурс, удерживаемый следующим.
Классический пример на Java:
final Object lock1 = new Object();
final Object lock2 = new Object();
Thread t1 = new Thread(() -> {
synchronized (lock1) { // t1 захватывает lock1
Thread.sleep(100);
synchronized (lock2) { } // t1 ждет lock2 (удерживаемый t2)
}
});
Thread t2 = new Thread(() -> {
synchronized (lock2) { // t2 захватывает lock2
Thread.sleep(100);
synchronized (lock1) { } // t2 ждет lock1 (удерживаемый t1) -> DEADLOCK
}
});
t1.start();
t2.start();
Способы предотвращения:
- Упорядочивание блокировок: Всегда захватывать locks в одном глобальном порядке (например, сначала
lock1, потомlock2). - Использование
tryLockс таймаутом изjava.util.concurrent.locks.ReentrantLock. - Избегание вложенных синхронизированных блоков.
- Использование высокоуровневых примитивов (
ConcurrentHashMap,ExecutorService).