Create a Custom CountDownLatch in Java
This post explains how a latch works internally using a simplified custom implementation.
Real-World Use Cases
- wait until all startup checks complete
- block request processing until warm-up jobs finish
- coordinate integration test phases
Simplified Implementation
public class CustomCountDownLatch {
private int counter;
public CustomCountDownLatch(int counter) {
this.counter = counter;
}
public synchronized void await() throws InterruptedException {
while (counter > 0) {
wait();
}
}
public synchronized void countDown() {
if (counter > 0) {
counter--;
if (counter == 0) {
notifyAll();
}
}
}
}
Java 8/11/17/21/25 Guidance
- Java 8+: Prefer built-in
java.util.concurrent.CountDownLatchin production. - JDK 11 / Java 17: Same API and usage model; no migration changes for latch semantics.
- Java 21+: Same API remains best choice even with virtual threads.
- Java 25: No migration pressure expected for latch semantics.
Production API Equivalent (CountDownLatch)
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class StartupChecks {
public static void main(String[] args) throws InterruptedException {
CountDownLatch latch = new CountDownLatch(3);
ExecutorService pool = Executors.newFixedThreadPool(3);
pool.submit(() -> runCheck("db", latch));
pool.submit(() -> runCheck("cache", latch));
pool.submit(() -> runCheck("queue", latch));
latch.await(); // wait for all checks
System.out.println("All checks complete. Start application.");
pool.shutdown();
}
static void runCheck(String name, CountDownLatch latch) {
try {
// perform check
} finally {
latch.countDown();
}
}
}
Key Takeaways
- Always use
whilearoundwait(). - Custom implementation is educational; built-in class is production-ready.
- Latch is one-time use; use
CyclicBarrier/Phaserfor repeated phases.