BackendBench
Coffee

Unravel › Java concepts › Concurrency

Concurrency

Latches, barriers and semaphores

These classes coordinate threads: CountDownLatch waits until N things have happened, CyclicBarrier makes threads wait for each other, Semaphore limits how many threads may enter at once.

Learn these first

At a glance

Mental model

Latch: a starting gate that opens only after everyone has checked in.

What happens, in order
  1. 1CountDownLatch latch = new CountDownLatch(3); each worker calls latch.countDown() when done; the coordinator calls latch.await() and continues when the count reaches 0It is single-use.
  2. 2CyclicBarrier(4, action) makes four threads call await() and all continue together, then it resets and can be reused for the next phase
  3. 3Semaphore sem = new Semaphore(5); sem.acquire(); try { ..} finally { sem.release(); } limits concurrency, for example to protect a connection pool or a rate-limited API.
  4. 4Phaser generalises the barrier to a changing number of parties and several phases
Remember
Watch out
Forgetting countDown on an error pathReusing a CountDownLatchAcquiring a semaphore permit and not releasing it on exceptionsAwaiting without timeout
Example (highlighted lines explain it)
import java.util.concurrent.*;public class StartUp {  static void runAll(ExecutorService pool, Runnable[] jobs) throws InterruptedException {    CountDownLatch done = new CountDownLatch(jobs.length);    Semaphore limit = new Semaphore(2);    for (Runnable job : jobs) {      pool.execute(() -> {        try { limit.acquire(); try { job.run(); } finally { limit.release(); } }        catch (InterruptedException e) { Thread.currentThread().interrupt(); }        finally { done.countDown(); }      });    }    if (!done.await(10, TimeUnit.SECONDS)) throw new IllegalStateException("timeout");  }}
  1. line 4 uses CountDownLatch, the core of Latches, barriers and semaphores
  2. line 5 uses Semaphore, the core of Latches, barriers and semaphores
  3. line 8 uses acquire, the core of Latches, barriers and semaphores
  4. line 10 uses countDown, the core of Latches, barriers and semaphores
  5. line 13 uses await, the core of Latches, barriers and semaphores
Read the full explanation (about 1 min)

These classes coordinate threads: CountDownLatch waits until N things have happened, CyclicBarrier makes threads wait for each other, Semaphore limits how many threads may enter at once.

A mental model

Latch: a starting gate that opens only after everyone has checked in. Barrier: hikers who wait at each junction until the whole group has arrived. Semaphore: a car park with 10 spaces: the 11th car waits until one leaves.

How it works

CountDownLatch latch = new CountDownLatch(3); each worker calls latch.countDown() when done; the coordinator calls latch.await() and continues when the count reaches 0. It is single-use.

CyclicBarrier(4, action) makes four threads call await() and all continue together, then it resets and can be reused for the next phase.

Semaphore sem = new Semaphore(5); sem.acquire(); try { ... } finally { sem.release(); } limits concurrency, for example to protect a connection pool or a rate-limited API.

Phaser generalises the barrier to a changing number of parties and several phases.

Going deeper

Always call release() and countDown() in finally; a failed worker that never counts down leaves the waiter stuck forever. Use await(timeout, unit) to avoid hanging.

A semaphore with one permit is a lock that any thread can release, which makes it a poor mutex but a useful signal.

Many of these needs are cleaner with CompletableFuture.allOf or ExecutorService.invokeAll; use the primitives when the coordination is not a simple fan-out and join.

Under the hood

They are built on AbstractQueuedSynchronizer (AQS), a lock-free state counter plus a queue of waiting threads. acquire tries to decrement the state with compare-and-set and parks the thread when it cannot.

Common mistakes

  • Forgetting countDown on an error path.
  • Reusing a CountDownLatch.
  • Acquiring a semaphore permit and not releasing it on exceptions.
  • Awaiting without timeout.

How Unravel recognises it

When you paste code, Unravel looks for these signs of latches, barriers and semaphores. Spotting them yourself is a good habit when you read unfamiliar code:

Part of a learning path

Related concepts

Frequently asked questions

What is Latches, barriers and semaphores?

These classes coordinate threads: CountDownLatch waits until N things have happened, CyclicBarrier makes threads wait for each other, Semaphore limits how many threads may enter at once.

What are the most common mistakes with Latches, barriers and semaphores?

Forgetting countDown on an error path. Reusing a CountDownLatch. Acquiring a semaphore permit and not releasing it on exceptions. Awaiting without timeout.

How can I see Latches, barriers and semaphores in real code?

Paste your own Java into Unravel and it will point out where latches, barriers and semaphores appears, explain how it works at the detail level you choose, and draw the flow of the code around it.