Java Programs›Multithreading›Wait for Workers Using CountDownLatch

Wait for Workers Using CountDownLatch in Java

intermediate·  Multithreading  ·  Concurrency

Problem

A CountDownLatch starts at a count; threads call countDown() as they finish, and any thread calling await() blocks until the count reaches zero.

Start three services on separate threads and let the main thread continue only after all three report that they're ready.

Input
3 services
Output
all started, then "accepting requests"

Java Program

Java
import java.util.concurrent.CountDownLatch; import java.util.concurrent.atomic.AtomicIntegerArray; public class CountDownLatchExample { public static void main(String[] args) throws InterruptedException { String[] services = {"database", "cache", "search"}; CountDownLatch ready = new CountDownLatch(services.length); // counts down from 3 AtomicIntegerArray started = new AtomicIntegerArray(services.length); for (int i = 0; i < services.length; i++) { final int id = i; new Thread(() -> { started.set(id, 1); // pretend to start the service ready.countDown(); // report "I'm up" }).start(); } ready.await(); // main blocks until all three have counted down for (int i = 0; i < services.length; i++) { System.out.println(services[i] + " started: " + (started.get(i) == 1)); } System.out.println("All services ready, accepting requests"); } }

Output

database started: true cache started: true search started: true All services ready, accepting requests

Core Logic

The latch is a one-time gate: it opens when the number of countDown() calls reaches the starting count.

How It Works
  1. 1new CountDownLatch(3) matches the number of services.
  2. 2Each worker marks its service as started, then calls ready.countDown().
  3. 3ready.await() blocks the main thread until the count is 0.
  4. 4Main then prints the status of every service, which is complete by that point.
Whichever order the three workers finish in, main only continues after the third countDown().
💡

Key Point: Unlike join(), a latch doesn't care which threads count down or whether they keep running afterwards — it just counts events.

Key Concepts

CountDownLatchcountDown()await()AtomicIntegerArray

Approach 2: A Single Start Signal

Java
import java.util.concurrent.CountDownLatch; import java.util.concurrent.atomic.AtomicInteger; public class CountDownLatchStartSignal { public static void main(String[] args) throws InterruptedException { CountDownLatch startSignal = new CountDownLatch(1); // one "go" for everybody CountDownLatch done = new CountDownLatch(4); AtomicInteger finished = new AtomicInteger(); for (int i = 0; i < 4; i++) { new Thread(() -> { try { startSignal.await(); // every runner waits at the start line finished.incrementAndGet(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } finally { done.countDown(); } }).start(); } System.out.println("Runners finished before the signal: " + finished.get()); startSignal.countDown(); // release all four at once done.await(); System.out.println("Runners finished after the signal: " + finished.get()); } }

Output

Runners finished before the signal: 0 Runners finished after the signal: 4

Core Logic

A latch with a count of 1 works as a starting pistol: many threads wait on it and are released together.

How It Works
  1. 1Each runner thread calls startSignal.await() before doing its work.
  2. 2Main checks that nothing has finished yet, then calls startSignal.countDown() once.
  3. 3A second latch, done, lets main wait until all four have finished.
Zero runners finish before the signal and four finish after it.
💡

Key Point: Latches can't be reset; for a gate that's used repeatedly, use CyclicBarrier or Phaser.

Key Concepts

latch of 1starting gatetwo latches

Interview Questions

What's the difference between CountDownLatch and CyclicBarrier?

A latch is used once and lets waiting threads continue when other threads count down. A barrier makes a fixed group of threads wait for each other and can be reused for several rounds.

What happens if a worker crashes before calling countDown?

The count never reaches zero and await() blocks forever. Call countDown() in a finally block, or use await(timeout, unit).

Learn the Concept

Related Programs