Получить доступ

Координация: семафоры, защёлки и барьеры

Semaphore, CountDownLatch, CyclicBarrier, Phaser и Exchanger — что каждый делает и когда выбирать.

Зачем готовые примитивы

Координацию можно собрать на wait/notify, но это легко сделать неправильно (потерянные сигналы, гонки). Пакет java.util.concurrent даёт проверенные высокоуровневые примитивы под типовые задачи — их и используют вместо ручной синхронизации.

Под капотом большинство построено на AbstractQueuedSynchronizer (AQS) — общем каркасе для очередей ожидающих потоков.

Semaphore

Semaphore хранит набор «пермитов»: acquire() забирает один (блокируясь, если их нет), release() возвращает. Это ограничитель одновременного доступа: семафор с N пермитами пускает не более N потоков сразу — например, ограничить число параллельных обращений к внешнему сервису или пул соединений.

Семафор с одним пермитом работает как (не реентерабельная!) блокировка. Поддерживает tryAcquire с таймаутом и режим fairness. Важно: release не обязан вызывать тот же поток, что acquire — это не владение, а счётчик разрешений.

Semaphore limit = new Semaphore(10); // не более 10 одновременно
limit.acquire();
try { callExternalService(); }
finally { limit.release(); }

CountDownLatch

CountDownLatch — одноразовый шлюз с счётчиком: потоки ждут на await(), пока счётчик не дойдёт до нуля через countDown(). Два классических применения: дождаться, пока N задач завершатся (главный поток ждёт), или одновременно стартовать N потоков по одному сигналу (защёлка на 1).

Ключевое ограничение — одноразовость: после достижения нуля защёлку нельзя переиспользовать.

CyclicBarrier

CyclicBarrier — точка встречи фиксированной группы потоков: каждый вызывает await() и блокируется, пока ВСЕ участники не подойдут, после чего они одновременно продолжают. В отличие от latch, барьер переиспользуем (циклический) и подходит для итеративных/фазовых вычислений.

Можно задать barrier action — код, который выполнится один раз при срабатывании барьера. Если один поток уходит по таймауту/прерыванию, барьер «ломается» (BrokenBarrierException) для всех.

Phaser и Exchanger

Phaser — гибкий барьер с динамическим числом участников (register/arriveAndDeregister) и явными фазами: подходит, когда количество потоков меняется между этапами, чего CyclicBarrier с фиксированным N не умеет. Exchanger — точка обмена данными между ровно двумя потоками: оба вызывают exchange(value) и получают значение друг друга.

Шпаргалка выбора: ограничить одновременный доступ — Semaphore; дождаться завершения событий (одноразово) — CountDownLatch; циклическая встреча фиксированной группы — CyclicBarrier; динамические фазы — Phaser; парный обмен — Exchanger.

Как отвечать на собеседовании

Чётко противопоставьте примитивы: Semaphore (N пермитов, ограничение доступа, release не привязан к потоку), CountDownLatch (одноразовый, дождаться N), CyclicBarrier (переиспользуемый рандеву группы + barrier action), Phaser (динамические участники/фазы), Exchanger (обмен между двумя). Упомяните, что многие построены на AQS.

Вопросы по теме

Читайте также

Закрытая бета

Знать тему — половина дела

На живом собеседовании sotto слышит вопрос интервьюера и показывает короткий ответ и план. Оставьте контакт — пришлём доступ и промокод.

  • Промокод на 2 часа — сверх пробных 30 минут
  • Программа для Windows — скачать сразу, войти — через Яндекс ID или VK ID
  • Прямая связь с разработчиком: что улучшить — сделаем