[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"question-mnogopotochnost-chto-takoe-livelock":3},{"id":4,"slug":5,"topicId":6,"topicSlug":7,"topicName":8,"topicEmoji":9,"question":10,"answer":11,"codeLang":12,"codeSrc":12,"important":12,"commonMistakes":12,"modernUsage":12,"difficulty":13,"tags":14,"related":20,"progress":21,"seo":22},246,"chto-takoe-livelock",8,"mnogopotochnost","Многопоточность","🔀","Что такое livelock?","\u003C!-- grade: 3\u002F5 — определение верное, но нет примера кода и отсутствуют способы предотвращения -->\n\n**Livelock** (активная блокировка) -- это разновидность взаимной блокировки, при которой потоки формально не заблокированы (их состояние не `BLOCKED` и не `WAITING`), но они не могут продвинуться дальше, потому что бесконечно реагируют на действия друг друга. В отличие от deadlock, потоки продолжают выполнять работу, но эта работа бесполезна -- КПД системы падает до нуля.\n\n### Как возникает livelock\n\nТипичный сценарий: два потока пытаются избежать deadlock, уступая друг другу ресурс, но логика уступки приводит к бесконечному циклу.\n\n| Характеристика | Deadlock | Livelock |\n|---|---|---|\n| Состояние потоков | `BLOCKED` \u002F `WAITING` | `RUNNABLE` |\n| Потребление CPU | Нулевое | Высокое (бесполезная работа) |\n| Обнаружение JVM | Возможно через `ThreadMXBean` | Автоматически не обнаруживается |\n| Внешние признаки | Приложение «зависло» | Приложение «крутится», но не продвигается |\n\n### Пример livelock\n\n\u003Cdetails>\n\u003Csummary>Пример: два потока уступают друг другу ложку\u003C\u002Fsummary>\n\n```java\npublic class LivelockExample {\n    static class Spoon {\n        private Diner owner;\n\n        Spoon(Diner owner) { this.owner = owner; }\n\n        synchronized void use() {\n            System.out.println(owner.name + \" ест!\");\n        }\n\n        synchronized void setOwner(Diner newOwner) {\n            this.owner = newOwner;\n        }\n\n        synchronized Diner getOwner() { return owner; }\n    }\n\n    static class Diner {\n        final String name;\n        boolean isHungry = true;\n\n        Diner(String name) { this.name = name; }\n\n        void eatWith(Spoon spoon, Diner partner) {\n            while (isHungry) {\n                \u002F\u002F Если ложка не у меня — жду\n                if (spoon.getOwner() != this) {\n                    try { Thread.sleep(1); } catch (InterruptedException e) { return; }\n                    continue;\n                }\n                \u002F\u002F Если партнёр тоже голоден — уступаю (вежливость!)\n                if (partner.isHungry) {\n                    System.out.println(name + \": \"\n                        + partner.name + \" тоже голоден, уступаю ложку.\");\n                    spoon.setOwner(partner);\n                    continue; \u002F\u002F \u003C-- Livelock: оба бесконечно уступают\n                }\n                \u002F\u002F Партнёр сыт — ем\n                spoon.use();\n                isHungry = false;\n                spoon.setOwner(partner);\n            }\n        }\n    }\n\n    public static void main(String[] args) {\n        Diner alice = new Diner(\"Алиса\");\n        Diner bob = new Diner(\"Боб\");\n        Spoon spoon = new Spoon(alice);\n\n        new Thread(() -> alice.eatWith(spoon, bob)).start();\n        new Thread(() -> bob.eatWith(spoon, alice)).start();\n        \u002F\u002F Оба потока бесконечно уступают друг другу ложку\n    }\n}\n```\n\n\u003C\u002Fdetails>\n\n### Способы предотвращения livelock\n\n1. **Случайная задержка (jitter)** -- добавить случайный интервал перед повторной попыткой, чтобы потоки «рассинхронизировались»:\n   ```java\n   Thread.sleep(ThreadLocalRandom.current().nextInt(10, 100));\n   ```\n2. **Приоритетная схема** -- ввести строгий порядок: один поток всегда имеет приоритет при конфликте.\n3. **Ограничение числа повторов** -- если поток уступил N раз подряд, он прекращает уступать.\n4. **Использование `Lock.tryLock(timeout)`** -- вместо бесконечного цикла ставить таймаут и обрабатывать ситуацию невозможности захвата.\n\n> **Аналогия из жизни.** Два человека встречаются в узком коридоре. Каждый, пытаясь быть вежливым, отходит в сторону -- но оба отходят в одну и ту же сторону. Они бесконечно двигаются из стороны в сторону, не продвигаясь в нужном направлении. Решение -- один из них останавливается и пропускает другого.\n\n> **На собеседовании.** Типичный вопрос: «Чем livelock отличается от deadlock?» Ключевое отличие: при deadlock потоки заблокированы и не потребляют CPU, при livelock потоки активны (`RUNNABLE`), потребляют CPU, но не совершают полезной работы. Livelock сложнее обнаружить, потому что приложение выглядит «живым». Часто livelock возникает как побочный эффект неудачной реализации предотвращения deadlock.","","middle",[15,16,17,18,19],"блокировка","deadlock","livelock","многопоточность","concurrency",[],null,{"title":23,"description":24,"ogTitle":25,"ogDescription":26,"keywords":27,"schemaAnswer":32,"featuredSnippetReady":33},"Что такое livelock в Java — отличие от deadlock — Gymterview","Livelock — взаимная блокировка, при которой потоки не останавливаются, а бесконечно реагируют друг на друга без продвижения. Отличие от deadlock и пример.","Livelock в Java — потоки работают, но ничего не делают","Livelock — потоки постоянно меняют состояние в ответ друг на друга, но не продвигаются. Часто возникает при попытке предотвратить deadlock.",[28,29,30,31],"livelock Java","livelock vs deadlock","livelock пример","взаимная блокировка потоков","Livelock — тип взаимной блокировки, при котором потоки выполняют бесполезную работу, зацикливаясь при попытке получить ресурсы. Состояния потоков постоянно меняются, но КПД системы падает до нуля. Аналогия: два человека в узком коридоре бесконечно уступают друг другу дорогу.",true]