skip to content

What are the key differences between CountDownLatch and CyclicBarrier, and when would you choose each?

level: seniorimportance: must knowfreq 78%

answer

  1. Latch = one-shot events; barrier = reusable parties
  2. Latch decouples signaller/waiter; barrier = mutual rendezvous
  3. Only barrier has a barrier action
  4. Barrier breaks (BrokenBarrierException); latch has no broken state
  5. Repeated rounds → barrier (or Phaser for dynamic counts)

basics

~20 s

A CountDownLatch is one-shot: any thread counts it down and waiters proceed at zero. A CyclicBarrier is reusable: a fixed set of threads wait for each other, then all go together and it resets. Use a latch for a single start/done signal, a barrier for repeated lockstep rounds.

solid answer

~50 s

They look similar but differ on several axes. CountDownLatch is single-use; once the count reaches zero it stays open and cannot reset. CyclicBarrier is reusable; it resets automatically after every release. With a latch the count is a number of events and any thread can countDown(), and the threads that count down need not be the ones that await; with a barrier the count is the number of participating parties, and each party both arrives and waits. A latch decouples signallers from waiters (1 waiter, N signallers, or vice versa); a barrier is a mutual rendezvous (N threads waiting on each other). Only the barrier has a barrier action that runs once when the last party arrives. On failure, a barrier breaks cleanly with BrokenBarrierException; a latch has no such notion. Choose a latch for a one-time 'go' or 'all done' signal; choose a barrier for iterative algorithms that synchronise every round.

go deeper

for a junior

Knows latch is for waiting on completion/start once, barrier is for threads waiting on each other repeatedly.

for a middle

Lists reusability, count meaning (events vs parties), and the barrier action as the main differences and picks the right one for a scenario.

for a senior

Articulates the full comparison including failure semantics (BrokenBarrierException) and happens-before, and justifies the choice for a given algorithm.

for a principal

Generalises to Phaser/CompletableFuture, weighs maintainability and failure recovery, and sets coordination patterns and guidance for a team.

## Why compare them Both `CountDownLatch` and `CyclicBarrier` live in `java.util.concurrent` and both make threads **wait**, so they are easily confused. The differences are about *who waits for whom*, *reusability*, and *failure handling*. ## Side-by-side | Aspect | CountDownLatch | CyclicBarrier | |---|---|---| | Reusability | **One-shot** — opens at zero, never resets | **Reusable** — auto-resets after each release | | What the count means | Number of **events** to wait for | Number of **parties** (threads) that meet | | Who advances it | **Any** thread via `countDown()` | Each **party** by calling `await()` | | Waiter vs signaller | Decoupled (waiters and counters are independent sets) | Same set: each party both arrives **and** waits | | Action on completion | None | Optional **barrier action**, run once by the last arriver | | Failure semantics | No 'broken' state | **`BrokenBarrierException`** on interrupt/timeout/reset/action-throw | | Typical shape | 1 waiter ↔ N signallers (or N waiters ↔ 1) | N ↔ N mutual rendezvous | ### Term definitions - **One-shot**: the synchronizer can be used exactly once; after it opens it is permanently open. - **Party**: one of the fixed N threads a barrier expects, each of which both arrives and waits. - **Rendezvous**: a meeting point where everyone waits until everyone arrives. - **Barrier action**: a `Runnable` the barrier runs once, in the last-arriving thread, before releasing the group. - **Broken barrier**: a state a barrier enters when a participant fails (interrupt/timeout/reset/action throws); all other waiters then throw `BrokenBarrierException` instead of hanging. ## Choosing between them **Use `CountDownLatch` when:** - A coordinator must wait until **N independent events** complete once (e.g. wait for N services to report ready at startup). Workers `countDown()`; coordinator `await()`. - You want a **single start gate**: many threads `await()` a latch of count 1; the controller `countDown()` to release them all simultaneously, once. - The signallers and waiters are **different** sets of threads. **Use `CyclicBarrier` when:** - A fixed group runs in **repeated synchronized rounds** (iterative simulations, matrix steps, multi-phase tests) and must regroup each round. - You want a **per-round hook** (the barrier action) to merge results or advance a phase between rounds. - The participants are a **fixed, mutually-waiting** set. ## A subtle gotcha A latch tolerates fewer or more `countDown()` calls than expected gracefully (extra calls are no-ops; too few means it never opens). A barrier requires **exactly** the configured number of parties to arrive each round; if one party dies without arriving, the others wait until interrupted/timed out and then break. For dynamically changing party counts, reach for **`Phaser`** instead, which generalises the barrier with registration/deregistration. ## Memory visibility (both) Both give *happens-before*: a latch publishes a signaller's pre-`countDown()` writes to a post-`await()` reader; a barrier publishes each party's pre-`await()` writes to all parties after the barrier (through the barrier action). So shared results computed before the sync point are safely visible after it.

  • You need a synchronization point where the number of participating threads changes between rounds. Which class fits?
    Phaser — it generalises CyclicBarrier with dynamic register()/arriveAndDeregister(), which neither latch nor barrier supports.
  • Can you emulate a one-shot start gate with a CyclicBarrier?
    Loosely yes (one round of N parties), but a CountDownLatch of count 1 is simpler and clearer for a pure start/done signal, and it does not require the waiters to also be the parties.

saying these in an interview costs you the question

  • Saying both are reusable, or both are one-shot
  • Claiming the latch count and barrier count mean the same thing (events vs parties)
  • Thinking only the waiting threads can countDown() a latch
  • Forgetting the barrier action exists only on CyclicBarrier
  • Not knowing a barrier can break, leaving the impression a failed party hangs the rest forever

context