Синхронизаторы 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? Для нескольких фаз и динамической регистрации участников.