Почему CountDownLatch нельзя использовать повторно

Вопрос проверяет, понимаете ли вы разницу между барьером на одно событие и переиспользуемым механизмом синхронизации.

CountDownLatch внутри держит счётчик, который уменьшается вызовами countDown() и никогда не увеличивается обратно. Как только счётчик дошёл до нуля, все текущие и будущие вызовы await() проходят сразу — сбросить состояние и «запустить заново» невозможно, нет метода reset.

Это нормально для сценария «дождаться, пока N потоков стартуют» или «дождаться завершения N задач один раз». Но если нужен повторяющийся барьер — например, синхронизировать несколько потоков на каждой итерации цикла — CountDownLatch не подходит: после первого использования объект бесполезен, нужно создавать новый экземпляр на каждый цикл.

CountDownLatch latch = new CountDownLatch(3);

for (int i = 0; i < 3; i++) { new Thread(() -> { doWork(); latch.countDown(); }).start(); }

latch.await(); System.out.println("все стартовали");

Спросят следом: чем это отличается от CyclicBarrier. CyclicBarrier рассчитан именно на повторное использование — после того как все потоки дошли до барьера, счётчик автоматически сбрасывается на исходное значение, и барьер можно проходить снова. У него есть опциональный Runnable, который выполняется одним из потоков в момент, когда барьер сработал — до того, как остальные потоки продолжат работу.

Если в коде латч создаётся один раз на уровне поля и вызывается из цикла — это баг, а не оптимизация.

Тренажёр: 600 вопросов, мок с таймером, план повторов

senior·base — что спрашивают на самом деле


В этом посте были ссылки, но мы их удалили по правилам Сетки