Ответ
Livelock — это состояние многопоточной программы, при котором потоки активно выполняют работу (не заблокированы, как при deadlock), но не могут прогрессировать из-за циклической реакции на действия друг друга. Они постоянно меняют своё состояние в ответ на изменения других потоков, но не продвигаются к завершению задачи.
Ключевое отличие от deadlock:
- Deadlock: Потоки заблокированы и ничего не делают, ожидая ресурсы.
- Livelock: Потоки активны, "работают", но застряли в бесконечном цикле взаимных уступок или повторных попыток.
Типичный пример ("вежливые" потоки): Два потока пытаются пройти через узкий коридор, каждый отступает в сторону, чтобы пропустить другого, и они бесконечно меняются местами.
Пример кода на Java:
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class LivelockExample {
private final Lock lock1 = new ReentrantLock(true); // Честная блокировка
private final Lock lock2 = new ReentrantLock(true);
public void operation1() {
while (true) {
if (lock1.tryLock()) {
System.out.println("Поток 1: захватил lock1");
try {
Thread.sleep(50); // Имитация работы
if (lock2.tryLock()) {
System.out.println("Поток 1: захватил lock2 -> УСПЕХ");
return; // Завершение работы
} else {
System.out.println("Поток 1: не получил lock2, отпускаю lock1");
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
lock1.unlock();
}
}
// Короткая пауза перед повторной попыткой
try { Thread.sleep(10); } catch (InterruptedException e) { break; }
}
}
// Аналогичный метод operation2() для второго потока, но пытающийся захватить lock2, затем lock1.
}
// Запуск двух потоков с этими методами может привести к livelock.
Как избежать livelock:
- Ввести детерминированный порядок захвата ресурсов (всегда сначала
lock1, потомlock2). - Использовать случайные или возрастающие таймауты между повторными попытками.
- Перепроектировать логику взаимодействия потоков, чтобы избежать циклической зависимости.