Synchronizers: Latch, Barrier, Semaphore, Phaser — Java Interview Guide | Cracked Java
Mid

Synchronizers: Latch, Barrier, Semaphore, Phaser

The coordination toolkit: CountDownLatch, CyclicBarrier, Semaphore, Phaser, and Exchanger — what each does and how they differ.

Prereqs: explicit-locks

Synchronizers are the higher-level coordination primitives in java.util.concurrent — objects that let threads wait for each other instead of just guarding shared state. Where a lock answers "only one thread in here at a time," a synchronizer answers "wait until N things have happened" or "let at most K threads through." Almost all of them are thin state machines built on AbstractQueuedSynchronizer (AQS), so they share the same fair/non-fair queuing and interruptible/timed await semantics.

The five tools

The toolkit splits cleanly by what each one counts and whether it resets:

  • CountDownLatch — a one-shot gate. Threads await() until a counter reaches zero via countDown(). Once open, it stays open; you throw it away after one use.
  • CyclicBarrier — a reusable rendezvous. A fixed number of threads call await(); when the last arrives the barrier trips, optionally runs a barrier action, then resets for the next round.
  • Semaphore — a counter of permits. acquire() blocks when no permits remain, release() returns one. Used to cap concurrency (a connection pool, a rate limiter).
  • Phaser — a reusable barrier with dynamic parties. Threads can register and deregister between phases, making it the right tool when the number of participants changes over time.
  • Exchanger — a two-thread rendezvous that swaps objects. Each thread offers an item and receives the other's.
CountDownLatch   N -> N-1 -> ... -> 0   (one-shot, never resets)
CyclicBarrier    parties arrive -> trip -> RESET -> repeat
Semaphore        permits: acquire-- / release++  (cap concurrency)
Phaser           parties register/deregister; advance phase 0,1,2...
Exchanger        thread A item  <-->  thread B item
What each synchronizer counts

Latch vs barrier: the classic confusion

The most-asked distinction: a latch waits for events and is one-directional and one-shot — one set of threads counts down while another set waits. A barrier waits for threads, where the same threads that arrive are the ones released, and it resets so you can reuse it across iterations. If a CyclicBarrier thread is interrupted or times out, every other waiter is released with a BrokenBarrierException; latches have no such "broken" state.

Pick by lifecycle: fixed count and single use → latch; recurring round-trip with a fixed crew → barrier; throttling access to a resource → semaphore; changing crew across rounds → phaser.

Questions

6 in this topic