Почему 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 — что спрашивают на самом деле
В этом посте были ссылки, но мы их удалили по правилам Сетки