How Does CountDownLatch Work in Java? A Deep Dive into Its Implementation
This article explains the purpose, differences, internal structure, and core methods of Java's CountDownLatch, shows how it leverages AQS for shared lock semantics, and provides a complete example demonstrating its usage in a thread‑synchronization scenario.
Overview
CountDownLatch is a synchronization aid that allows one or more threads to wait until a set of operations performed by other threads completes. Unlike CyclicBarrier, which lets a group of threads wait for each other at a reusable barrier, a CountDownLatch can be used only once because its count cannot be reset.
Key Differences from CyclicBarrier
CountDownLatch lets 1 or N threads wait for other threads to finish; CyclicBarrier requires N threads to wait for each other.
The latch count is immutable after construction, while CyclicBarrier’s count can be reused, making it a true cyclic barrier.
Implementation Details
The latch is built on a private static inner class Sync that extends AbstractQueuedSynchronizer (AQS). The only public constructor is:
public CountDownLatch(int count) {
if (count < 0) throw new IllegalArgumentException("count < 0");
this.sync = new Sync(count);
} Syncholds the synchronization state (the count) and overrides the essential AQS methods:
protected int tryAcquireShared(int acquires) {
return (getState() == 0) ? 1 : -1;
}
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;
}
}await()
The await() method blocks the calling thread until the count reaches zero:
public void await() throws InterruptedException {
sync.acquireSharedInterruptibly(1);
}Internally it calls acquireSharedInterruptibly of AQS, which repeatedly invokes tryAcquireShared and, if the count is not zero, parks the thread until it is released.
countDown()
Each call to countDown() decrements the latch count and potentially releases waiting threads:
public void countDown() {
sync.releaseShared(1);
}The overridden tryReleaseShared reduces the state and returns true when the new state is zero, triggering the wake‑up of all waiting threads.
Practical Example
The following program simulates a meeting scenario where a boss thread waits for five employee threads to arrive before proceeding:
public class CountDownLatchTest {
private static CountDownLatch latch = new CountDownLatch(5);
static class BossThread extends Thread {
@Override
public void run() {
System.out.println("Boss is waiting, count=" + latch.getCount());
try {
latch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("All arrived, meeting starts...");
}
}
static class EmployeeThread extends Thread {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + " arrived.");
latch.countDown();
}
}
public static void main(String[] args) {
new BossThread().start();
for (int i = 0; i < latch.getCount(); i++) {
new EmployeeThread().start();
}
}
}Running the program prints the boss waiting message, each employee arrival, and finally the boss’s confirmation that all participants are present.
Conclusion
CountDownLatch implements a one‑time shared lock using AQS. It is created with an initial count representing the number of required events. Threads calling await() block until the count reaches zero, while other threads invoke countDown() to decrement the count. Because the count cannot be reset, a new latch must be instantiated for repeated use.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Programmer DD
A tinkering programmer and author of "Spring Cloud Microservices in Action"
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
