В чем разница между Deadlock и Livelock в многопоточном программировании?

«В чем разница между Deadlock и Livelock в многопоточном программировании?» — вопрос из категории Многопоточность, который задают на 10% собеседований IOS Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

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

Livelock (активная блокировка) — состояние, при котором потоки не блокируются полностью, а продолжают выполнять работу (например, освобождать и повторно захватывать ресурсы), но не продвигаются к завершению из-за циклической реакции друг на друга.

Ключевое отличие: При deadlock потоки пассивно ожидают, при livelock — активно, но безуспешно работают.

Пример Deadlock (Swift/Foundation):

let lock1 = NSLock()
let lock2 = NSLock()

DispatchQueue.global().async {
    lock1.lock()
    Thread.sleep(forTimeInterval: 0.1)
    lock2.lock() // Блокировка: lock2 удерживается другим потоком
    // Критическая секция
    lock2.unlock()
    lock1.unlock()
}

DispatchQueue.global().async {
    lock2.lock()
    Thread.sleep(forTimeInterval: 0.1)
    lock1.lock() // Блокировка: lock1 удерживается другим потоком
    // Критическая секция
    lock1.unlock()
    lock2.unlock()
}

Пример Livelock (концептуальный):

Два потока пытаются избежать deadlock, освобождая ресурс при обнаружении конфликта, но делают это синхронно, попадая в бесконечный цикл «уступить-проверить-повторить».

Практические меры предотвращения:

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