Короткий ответ
Deadlock (взаимная блокировка) — это ситуация, когда два или более потоков навсегда блокируют друг друга: каждый поток удерживает ресурс (монитор, блокировку), который нужен другому, и одновременно ждёт ресурс, удерживаемый другим. В результате программа «зависает», хотя потоки не завершились и не упали с ошибкой.
Как это работает подробнее
Классический сценарий в Java: поток 1 захватывает монитор объекта A и хочет войти в блок по объекту B, а поток 2 одновременно захватывает B и хочет войти в блок по A.
Для возникновения deadlock нужно четыре условия Коффмана: взаимное исключение, удержание и ожидание, отсутствие вытеснения и циклическое ожидание. Достаточно устранить хотя бы одно из них, чтобы взаимной блокировки не было.
- Похожее явление — livelock: потоки не заблокированы, активно меняют состояние, но из-за взаимных уступок не продвигаются вперёд.
Пример кода
DeadlockExample.java
public class DeadlockExample {
private static final Object A = new Object();
private static final Object B = new Object();
public static void main(String[] args) {
// Поток 1: держит A и хочет B
new Thread(() -> {
synchronized (A) {
synchronized (B) {
System.out.println("Поток 1");
}
}
}).start();
// Поток 2: захватывает блокировки в обратном порядке
new Thread(() -> {
synchronized (B) {
synchronized (A) {
System.out.println("Поток 2");
}
}
}).start();
}
}Что использовать на практике
- Захватывай блокировки во всех потоках в едином фиксированном порядке (и освобождай в обратном) — это разрывает циклическое ожидание.
- Используй
ReentrantLock.tryLock(timeout): не удалось захватить — освободи уже захваченные ресурсы и повтори попытку.