Синхронизаторы java.util.concurrent

КлассМодельПовторное использование
CountDownLatch(n)один или несколько ждут N завершенийнет
CyclicBarrier(n)N участников встречаются на рубежеда
Phaserфазы и динамическое число участниковда
Semaphore(n)не более N одновременных пользователейда
Exchanger<T>два потока обмениваются значениямида

CountDownLatch

CountDownLatch ready = new CountDownLatch(3);
 
for (int i = 0; i < 3; i++) {
    pool.execute(() -> {
        try {
            initializePart();
        } finally {
            ready.countDown();
        }
    });
}
 
ready.await();
startApplication();

Счетчик только уменьшается и не сбрасывается. countDown() в finally защищает от вечного ожидания, но ошибку задачи нужно передать отдельно.

CyclicBarrier

CyclicBarrier barrier = new CyclicBarrier(3, this::mergeRound);
// каждый участник после своей части:
barrier.await();

Если ожидание одного участника оборвалось или истек timeout, barrier становится broken; другие получат BrokenBarrierException.

Выбор

  • ждать окончаний → latch;
  • синхронизировать равноправных участников по раундам → barrier;
  • менять число участников и фаз → phaser;
  • ограничить доступ → Семафор в Java;
  • передать работу → обычно BlockingQueue, а не синхронизатор.

На собеседовании

  • Можно ли переиспользовать CountDownLatch? Нет.
  • Кто уменьшает latch? Выполнившие работу потоки; ожидающие вызывают await.
  • Что делает barrier cyclic? После успешного прохода всех участников пригодна для новой фазы.
  • Когда нужен Phaser? Для нескольких фаз и динамической регистрации участников.