Skip to main content
  1. Java Concurrency (java.util.concurrent)/

CountDownLatch

2 mins

CountDownLatch is a simple yet powerful synchronizer that allows one or more threads to wait until a specific number of operations have completed in other threads.

Source Code #

View Source on GitHub

Implementation Mechanism #

CountDownLatch is an elegant implementation of AQS in Shared Mode. The state variable represents the initial count. When a thread calls countDown(), the state is decremented via CAS. Threads calling await() are parked in the wait queue until the state reaches exactly zero.

// Shared Mode acquisition in CountDownLatch.Sync
protected int tryAcquireShared(int acquires) {
    return (getState() == 0) ? 1 : -1;
}

// Shared Mode release in CountDownLatch.Sync
protected boolean tryReleaseShared(int releases) {
    for (;;) {
        int c = getState();
        if (c == 0) return false;
        int nextc = c - 1;
        if (compareAndSetState(c, nextc))
            return nextc == 0;
    }
}

Canonical Usage #

When to use: Use CountDownLatch for one-time initialization or start-up coordination. It is NOT reusable; once the count reaches zero, the latch is open forever.

Common Patterns:

  • Startup Synchronization: A main thread waits until several background services have initialized before proceeding.
  • Simultaneous Start: Multiple threads wait on a “start gate” to begin an operation simultaneously.
  • Unit Testing Concurrent Code: Ensuring multiple threads have finished their tasks before asserting results in a test.
// Main thread waits for 5 background tasks to finish initialization
CountDownLatch startGate = new CountDownLatch(5);

// In each background task
executor.execute(() -> {
    try {
        doInitialize();
    } finally {
        startGate.countDown(); // Signal that this task is ready
    }
});

// Main thread blocks here until count reaches 0
startGate.await();
System.out.println("All tasks initialized. Proceeding...");

Difference from CyclicBarrier #

  • One-time only: CountDownLatch cannot be reset.
  • Unbalanced: One thread can wait for many other threads to countDown(). In a CyclicBarrier, everyone must wait for everyone else.