Что такое deadlock и как его предотвращать?
Deadlock — циклическое ожидание: поток A держит замок 1 и ждёт замок 2, поток B держит 2 и ждёт 1. Предотвращают единым порядком захвата, tryLock с таймаутом и откатом, короткими критическими секциями без вызова чужого кода под замком.
- Четыре условия Коффмана: взаимное исключение, удержание с ожиданием, нет отбора, цикл
- Найти — дамп потоков (jstack): «Found one Java-level deadlock»
- Сам не разрешается: потоки стоят вечно
А ещё Livelock — потоки активны, но уступают друг другу без прогресса
Подробно
Классический пример — перевод денег:
void transfer(Account from, Account to, int sum) {
synchronized (from) {
synchronized (to) { ... }
}
}
// поток 1: transfer(a, b) поток 2: transfer(b, a) → взаимная блокировка
Условия взаимоблокировки (все четыре одновременно): ресурс используется монопольно; поток держит одно и ждёт другое; ресурс нельзя отобрать; ожидание образует цикл. Достаточно сломать любое.
Способы предотвращения:
- глобальный порядок захвата — например, по id счёта: сначала меньший; цикла не возникнет;
- tryLock с таймаутом (ReentrantLock): не получилось — отпустить захваченное и повторить позже;
- не вызывать чужой код под замком — колбэк может захватить неизвестные замки;
- один замок вместо нескольких, или структуры без блокировок.
Диагностика: jstack <pid> или дамп из VisualVM — JVM сама находит цикл среди мониторов и ReentrantLock и печатает, кто кого ждёт. Программно — ThreadMXBean.findDeadlockedThreads().
Родственные проблемы: livelock (потоки бесконечно уступают друг другу), starvation (поток никогда не получает ресурс).
Что хотят услышать
- Определение и пример.
- Условия возникновения.
- Порядок захвата, tryLock, отсутствие чужого кода под замком.
- Как найти в работающем приложении.
Частые ошибки
- Надеяться, что JVM разорвёт взаимоблокировку сама.
Проверьте себя
Один верный вариант. Подумайте, потом откройте ответ.
Показать варианты и ответ
- ✗Ситуация, когда поток бесконечно выполняет цикл и занимает всё процессорное время, а JVM потом сама разрешает её
- ✗Нехватка памяти под стеки потоков
- ✗Взаимная блокировка; лечится увеличением числа потоков в пуле до числа замков
- ✓Взаимная блокировка; предотвращают единым порядком захвата и tryLock с таймаутом
Что спросят дальше
- Как получить thread dump?
- Чем deadlock отличается от livelock?
Разбор темы
- Явные блокировки: ReentrantLock, RW и Condition
Когда synchronized мало, ReentrantLock с tryLock/fairness, ReadWriteLock и StampedLock, Condition вместо wait/notify.
Связанные вопросы
Разбор собеседования с sotto
После собеседования sotto разбирает разговор: оценка, каждый вопрос — хорошо, частично или слабо, чего не хватило в ответе и над чем поработать к следующему разу. Первые 30 минут бесплатно.