Найти в Дзене
Записки о Java

CountDownLatch в Java: 2 практичных примера для собеседования

CountDownLatch — это один из самых полезных классов в пакете java.util.concurrent. Он позволяет одному или нескольким потокам ждать, пока другие потоки не завершат определённую работу.
На собеседованиях его часто спрашивают, потому что он демонстрирует понимание координации потоков без блокировок. Давайте разберём два реалистичных сценария, которые вы легко сможете объяснить на интервью. CountDownLatch latch = new CountDownLatch(3); // счётчик = 3 ⚠️ Счётчик не может быть увеличен — только уменьшен. Это «одноразовый барьер». Задача:
Представьте, что ваше приложение зависит от трёх внешних сервисов (база данных, кэш, очередь). Вы не хотите запускать основной цикл, пока все они не готовы. Задача:
Вы отправляете запросы к трём API одновременно и хотите обработать результаты только после того, как все ответят. Пример, рассмотренный в статье, можно найти по адресу:
Оглавление
Рисунок: CountDownLatch в Java
Рисунок: CountDownLatch в Java

Как дождаться завершения нескольких потоков — просто и надёжно

CountDownLatch — это один из самых полезных классов в пакете java.util.concurrent. Он позволяет одному или нескольким потокам ждать, пока другие потоки не завершат определённую работу.
На собеседованиях его часто спрашивают, потому что он демонстрирует понимание
координации потоков без блокировок.

Давайте разберём два реалистичных сценария, которые вы легко сможете объяснить на интервью.

🔧 Быстрый обзор: как работает CountDownLatch

CountDownLatch latch = new CountDownLatch(3); // счётчик = 3

  • Каждый раз, когда какой-то поток вызывает latch.countDown(), счётчик уменьшается на 1.
  • Поток, вызвавший latch.await(), блокируется, пока счётчик не станет 0.
  • После этого все ожидающие потоки разблокируются и продолжают работу.
⚠️ Счётчик не может быть увеличен — только уменьшен. Это «одноразовый барьер».

Пример 1: Запуск приложения после инициализации сервисов

Задача:
Представьте, что ваше приложение зависит от трёх внешних сервисов (база данных, кэш, очередь). Вы не хотите запускать основной цикл, пока все они не готовы.

Решение с CountDownLatch:

Рисунок: приложение AppStartup, часть 1
Рисунок: приложение AppStartup, часть 1
Рисунок: приложение AppStartup, часть 2
Рисунок: приложение AppStartup, часть 2

Пример 2: Параллельное выполнение задач с ожиданием результата

Задача:
Вы отправляете запросы к трём API одновременно и хотите обработать результаты
только после того, как все ответят.

Решение:

Рисунок: приложение ParallelApiCalls, часть 1
Рисунок: приложение ParallelApiCalls, часть 1
Рисунок: приложение ParallelApiCalls, часть 2
Рисунок: приложение ParallelApiCalls, часть 2

Важные нюансы

  1. await() может выбросить InterruptedException → всегда обрабатывайте его.
  2. CountDownLatch — не переиспользуемый. После достижения нуля его нельзя «сбросить».Если нужен многоразовый барьер — смотрите в сторону CyclicBarrier.
  3. Не путайте с join():join() ждёт конкретный поток,
    CountDownLatch ждёт
    N событий, независимо от того, в каких потоках они произошли.

Заключение

Пример, рассмотренный в статье, можно найти по адресу:
https://github.com/ShkrylAndrei/blog_yandex/tree/main/src/main/java/info/examples/count_down_latch