πŸ”₯ Launch Offer: Interview Preparation Bundle @ β‚Ή2,499 β‚Ή9,999 β€’ 75% OFF. Offer expires in πŸ”₯ Launch Offer: Interview Preparation Bundle @ β‚Ή2,499 β‚Ή9,999 β€’ 75% OFF. Offer expires in Interview Preparation Bundle @ β‚Ή2,499 β‚Ή9,999

00:00:00 Get Bundle
home java countdownlatch-in-java-complete-guide-with-real-world-examples-executorservice-interview-questions-and-best-practices
Interview guide Java 29 sections

CountDownLatch in Java: Complete Guide with Real-World Examples, ExecutorService, Interview Questions, and Best Practices

Concurrency is one of the most important topics for Java backend developers. During interviews at companies like Oracle, Walmart, Amazon, Microsoft, and many product-based companies, you may be…

Start reading
By javainterviewprep June 14, 2026 6 min read

Concurrency is one of the most important topics for Java backend developers. During interviews at companies like Oracle, Walmart, Amazon, Microsoft, and many product-based companies, you may be asked questions such as:

  • What is CountDownLatch?
  • Why do we use it?
  • How does it work with ExecutorService?
  • Does the latch count have to equal the thread count?
  • Why should countDown() always be called inside a finally block?

In this guide, you’ll learn everything about CountDownLatch with simple explanations, diagrams, real-world use cases, and complete code examples.


What is CountDownLatch?

CountDownLatch is a synchronization utility provided by Java that allows one or more threads to wait until a specified number of tasks have completed.

Think of it as a countdown timer.

Initial Count = 3

Task 1 Completed
Count = 2

Task 2 Completed
Count = 1

Task 3 Completed
Count = 0

↓

Waiting thread continues

The waiting thread remains blocked until the count reaches zero.


Real-World Analogy

Imagine a teacher is waiting for three students to submit their assignments.

Teacher

Waiting...

Student A βœ”
Student B βœ”
Student C βœ”

↓

Teacher starts checking papers

The teacher cannot begin until all three students have submitted their work.

CountDownLatch behaves exactly like this.


Why Do We Need CountDownLatch?

Suppose an e-commerce application needs information from multiple services before displaying the checkout page.

Checkout Page

β”‚

β–Ό

Product Service
User Service
Order Service

β”‚
β–Ό

Wait until all complete

β”‚
β–Ό

Return Response

Without CountDownLatch, coordinating multiple threads becomes difficult.


How CountDownLatch Works

There are only two important methods.

1. countDown()

Reduces the count by one.

latch.countDown();

Example:

Count = 3

Task 1 Finished

Count = 2

2. await()

Makes the current thread wait.

latch.await();

The waiting thread resumes only when the count becomes zero.


Basic Example

CountDownLatch latch = new CountDownLatch(3);

Thread 1
Thread 2
Thread 3

↓

Each thread calls

latch.countDown();

↓

Count becomes 0

↓

Main thread continues

Complete Example with ExecutorService

ExecutorService executor = Executors.newFixedThreadPool(3);

CountDownLatch latch = new CountDownLatch(3);

executor.submit(() -> {
try {
System.out.println("Calling Product Service");
} finally {
latch.countDown();
}
});

executor.submit(() -> {
try {
System.out.println("Calling User Service");
} finally {
latch.countDown();
}
});

executor.submit(() -> {
try {
System.out.println("Calling Order Service");
} finally {
latch.countDown();
}
});

latch.await();

System.out.println("All services completed");

executor.shutdown();

Execution Flow

Main Thread

β”‚

β–Ό

Submit 3 Tasks

β”‚

β–Ό

Thread 1 β†’ Product Service

Thread 2 β†’ User Service

Thread 3 β†’ Order Service

β”‚

β–Ό

Each task calls countDown()

3

↓

2

↓

1

↓

0

↓

await() returns

↓

Main thread continues

Does CountDownLatch Count Have to Equal the Thread Count?

No.

This is one of the most commonly asked interview questions.

Many developers think these two values must be the same.

They do not represent the same thing.

Thread Pool

ExecutorService executor =
Executors.newFixedThreadPool(3);

The number 3 means

Maximum 3 threads can execute tasks at the same time.


CountDownLatch

CountDownLatch latch =
new CountDownLatch(10);

The number 10 means

Wait until 10 tasks have completed.

These are completely independent.


Example

ExecutorService

3 Threads

CountDownLatch

10 Tasks

Execution

Round 1

Thread 1 β†’ Task 1

Thread 2 β†’ Task 2

Thread 3 β†’ Task 3

↓

Round 2

Thread 1 β†’ Task 4

Thread 2 β†’ Task 5

Thread 3 β†’ Task 6

↓

Round 3

Thread 1 β†’ Task 7

Thread 2 β†’ Task 8

Thread 3 β†’ Task 9

↓

Round 4

Thread 1 β†’ Task 10

Only three tasks run simultaneously because there are only three worker threads.

However, the latch waits for all ten tasks.

Latch Count

10

↓

9

↓

8

↓

...

↓

1

↓

0

↓

Main Thread Continues

Real-World Use Case 1: Processing 10,000 Orders

Suppose an e-commerce company receives 10,000 orders.

Creating 10,000 threads would waste memory.

Instead,

ExecutorService executor =
Executors.newFixedThreadPool(20);

CountDownLatch latch =
new CountDownLatch(10000);

Execution

20 Worker Threads

↓

Process first 20 orders

↓

Threads become free

↓

Process next 20 orders

↓

Repeat

↓

10,000 Orders Completed

↓

Latch becomes 0

↓

Generate Final Report

Real-World Use Case 2: Sending Emails

5000 Emails

↓

10 Threads

↓

Send Emails

↓

Every task

countDown()

↓

Wait for all emails

↓

Generate Success Report

Real-World Use Case 3: Salary Slip Generation

15000 Employees

↓

25 Worker Threads

↓

Generate Salary Slip

↓

countDown()

↓

All Completed

↓

Create ZIP File

↓

Notify Employees

What Happens If One Task Fails?

Suppose three services are running.

Product Service βœ”

Order Service βœ–

User Service βœ”

Should the waiting thread continue?

Yes.

But only if countDown() is always executed.


Why countDown() Should Always Be Inside finally

Correct way

executor.submit(() -> {

try {

orderService.getOrders();

} catch (Exception e) {

System.out.println("Order Failed");

} finally {

latch.countDown();

}

});

Execution

Initial Count = 3

↓

Product Success

Count = 2

↓

Order Failed

finally executes

Count = 1

↓

User Success

Count = 0

↓

await() returns

Even though one task failed, the waiting thread is released.


What Happens If countDown() Is Not Inside finally?

Wrong implementation

executor.submit(() -> {

try {

orderService.getOrders();

latch.countDown();

} catch (Exception e) {

System.out.println("Failed");

}

});

Suppose the service throws an exception.

Execution

Initial Count = 3

↓

Product Success

Count = 2

↓

Order Failed

countDown() skipped

Count still = 2

↓

User Success

Count = 1

↓

await()

Waiting...

Waiting...

Waiting...

Forever

The latch never reaches zero.

The waiting thread never continues.

This is one of the most common mistakes developers make.


Best Practice

Always write your task like this.

executor.submit(() -> {

try {

// Business Logic

} catch (Exception e) {

// Handle Exception

} finally {

latch.countDown();

}

});

No matter what happens,

  • Success
  • Failure
  • Exception

the latch is always decremented.


Common Interview Questions

1. Does CountDownLatch count have to equal the thread count?

No.

Thread count controls how many tasks execute simultaneously.

Latch count controls how many task completions to wait for.


2. Can one thread call countDown() multiple times?

Yes.

The latch only counts method calls.

It does not track which thread called them.


3. Can CountDownLatch be reused?

No.

Once the count reaches zero, it cannot be reset.

For reusable synchronization, use CyclicBarrier or Phaser.


4. What happens if countDown() is never called?

The waiting thread remains blocked forever unless you use a timed wait.

latch.await(5, TimeUnit.SECONDS);

5. Does countDown() block the thread?

No.

It simply decrements the count and returns immediately.

Only await() blocks.


Common Mistakes

❌ Setting latch count equal to thread count without considering the number of tasks.

❌ Forgetting to call countDown().

❌ Calling countDown() only after successful execution.

❌ Never shutting down the executor.

❌ Assuming CountDownLatch can be reused.


When Should You Use CountDownLatch?

Use it when you need to wait for multiple independent tasks to finish before continuing.

Examples include:

  • Loading data from multiple microservices
  • Processing thousands of orders
  • Sending bulk emails
  • Importing CSV files
  • Parallel file processing
  • Batch jobs
  • Report generation
  • Running initialization tasks during application startup

CountDownLatch at a Glance

FeatureDescription
PurposeWait for multiple tasks to finish
Blocks ThreadYes (await())
Decrements CountcountDown()
Reusable❌ No
Thread-safeβœ… Yes
Commonly Used WithExecutorService, thread pools, batch processing
Best PracticeAlways call countDown() inside finally

Conclusion

CountDownLatch is a simple yet powerful synchronization utility that helps coordinate multiple concurrent tasks. It is especially useful when a thread must wait for several independent operationsβ€”such as API calls, file processing, or batch jobsβ€”to finish before moving on.

Remember these key points:

  • await() blocks until the count reaches zero.
  • countDown() decreases the count by one.
  • The latch count represents the number of task completions, not the number of threads.
  • The thread pool size and latch count are independent.
  • Always place countDown() in a finally block to prevent deadlocks if a task throws an exception.
  • A CountDownLatch is a one-time synchronization aid; once the count reaches zero, it cannot be reset.

Understanding these concepts will help you write reliable concurrent code and confidently answer CountDownLatch questions in Java interviews.