[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"question-mnogopotochnost-chto-takoe-completionservice-i-kogda-ego-primenyat":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":21,"progress":22,"seo":23},303,"chto-takoe-completionservice-i-kogda-ego-primenyat",8,"mnogopotochnost","Многопоточность","🔀","Что такое CompletionService и когда его применять?","\u003C!-- grade: 5\u002F5 — отличный ответ с мотивацией и практическими примерами -->\n\n`CompletionService\u003CV>` — это интерфейс из `java.util.concurrent`, который отделяет **создание** асинхронных задач от **получения** их результатов. Он позволяет получать результаты **в порядке их готовности**, а не в порядке запуска.\n\nОсновная реализация — `ExecutorCompletionService`.\n\n**Проблема без CompletionService:**\n\n```java\nList\u003CFuture\u003CString>> futures = new ArrayList\u003C>();\nfor (String url : urls) {\n    futures.add(executor.submit(() -> fetch(url)));\n}\n\n\u002F\u002F Обрабатываем в порядке ЗАПУСКА — если futures.get(0) самая медленная,\n\u002F\u002F все остальные результаты ждут!\nfor (Future\u003CString> future : futures) {\n    String result = future.get(); \u002F\u002F блокируется на КОНКРЕТНОЙ задаче\n    process(result);\n}\n```\n\n**Решение с CompletionService:**\n\n```java\nCompletionService\u003CString> cs = new ExecutorCompletionService\u003C>(executor);\n\nfor (String url : urls) {\n    cs.submit(() -> fetch(url));\n}\n\n\u002F\u002F Обрабатываем в порядке ЗАВЕРШЕНИЯ — кто первый закончил, того первым обработали\nfor (int i = 0; i \u003C urls.size(); i++) {\n    Future\u003CString> future = cs.take(); \u002F\u002F Берём первый завершившийся\n    String result = future.get();       \u002F\u002F Гарантированно не заблокируется\n    process(result);\n}\n```\n\n**Основные методы:**\n\n| Метод | Описание |\n|---|---|\n| `submit(Callable\u003CV>)` | Отправить задачу на выполнение |\n| `take()` | Блокирующее ожидание первой завершённой задачи |\n| `poll()` | Неблокирующее получение (или `null`) |\n| `poll(timeout, unit)` | Ожидание с таймаутом |\n\n\u003Cdetails>\n\u003Csummary>Код: получение первого успешного результата\u003C\u002Fsummary>\n\n```java\nCompletionService\u003CString> cs = new ExecutorCompletionService\u003C>(executor);\n\ncs.submit(() -> fetchFromServerA());\ncs.submit(() -> fetchFromServerB());\ncs.submit(() -> fetchFromServerC());\n\nfor (int i = 0; i \u003C 3; i++) {\n    try {\n        Future\u003CString> future = cs.take();\n        String result = future.get();\n        if (result != null) {\n            executor.shutdownNow(); \u002F\u002F Отменяем оставшиеся\n            return result;\n        }\n    } catch (ExecutionException e) {\n        \u002F\u002F Эта задача упала — пробуем следующую\n    }\n}\n```\n\n\u003C\u002Fdetails>\n\n**Ключевые особенности:**\n- Решает проблему «head-of-line blocking» — не нужно ждать медленную задачу, чтобы обработать быструю.\n- Внутри использует `LinkedBlockingQueue` для хранения завершённых `Future`.\n- Не владеет `Executor` — закрытие `ExecutorService` выполняется отдельно.\n- Идеально для scatter-gather: запустить много запросов и обработать ответы по мере поступления.\n\n**Частые ошибки:**\n- Забыть вызвать `take()`\u002F`poll()` для всех задач — утечка памяти.\n- Не вызывать `future.get()` после `take()` — ошибки не обнаружатся.\n- Использование для одной задачи — избыточно.\n\n> **Аналогия:** без `CompletionService` — это получение багажа в аэропорту по номеру очереди: «подождите, пока не выдадут чемодан номер 1, потом номер 2...» С `CompletionService` — это багажная лента: кто первый приехал, того первым и забрали.\n\n> **На собеседовании** стоит сравнить с `CompletableFuture.anyOf()`: `CompletionService` удобнее, когда нужно обработать **все** результаты по мере готовности, а `anyOf` — когда нужен только первый. С Virtual Threads часть сценариев заменяется на `StructuredTaskScope`.","","senior",[15,16,17,18,19,20],"фазы","синхронизатор","барьер","Phaser","динамические-участники","concurrency",[],null,{"title":24,"description":25,"ogTitle":26,"ogDescription":27,"keywords":28,"schemaAnswer":34,"featuredSnippetReady":35},"Phaser в Java — многофазный синхронизатор с динамическими участниками — Gymterview","Phaser (Java 7) объединяет CountDownLatch и CyclicBarrier: несколько фаз, динамическое число участников, иерархическая структура. Примеры использования.","Phaser — динамический многофазный барьер в Java","Phaser поддерживает несколько фаз синхронизации с динамическим числом участников. Комбинирует CountDownLatch и CyclicBarrier.",[29,30,31,32,33],"Phaser Java","многофазная синхронизация","arriveAndAwaitAdvance","динамические участники","Phaser vs CyclicBarrier","Phaser (Java 7) — синхронизатор, объединяющий CountDownLatch и CyclicBarrier. Поддерживает несколько фаз (этапов), динамическое добавление\u002Fудаление участников (register\u002FarriveAndDeregister), иерархическую структуру (tiered phasers). Метод arriveAndAwaitAdvance() — основной: «я завершил фазу и жду остальных». Переопределение onAdvance() управляет количеством фаз. Используется в ETL, map-reduce, игровых серверах.",true]