Using CountDownLatch in Java: A Deep Dive with Code Examples and Demos

Using CountDownLatch in Java: A Deep Dive with Code Examples and Demos

When developing multi-threaded applications in Java, managing synchronization between threads can be a challenging task. One of the most powerful tools in Java’s concurrency toolkit is CountDownLatch. This utility allows you to synchronize one or...

1. Understanding CountDownLatch in Java

CountDownLatch is a part of the java.util.concurrent package and is used to synchronize one or more threads, forcing them to wait until a set of operations being performed in other threads completes. It's initialized with a count, and every time a thread completes its task, it decrements this count. Once the count reaches zero, the waiting threads are released.

1.1 What is CountDownLatch?

Image

CountDownLatch is a synchronization aid that allows one or more threads to wait until a set of operations in other threads completes. Imagine you have multiple services that must be started before your main application can begin. With CountDownLatch, you can make the main thread wait until all services are up and running.

1.2 How Does CountDownLatch Work?

Image

The working mechanism of CountDownLatch revolves around a counter initialized to a specific value. Each time a thread completes its execution, it calls the countDown() method, which decrements the counter. When the counter reaches zero, the await() method releases all waiting threads, allowing them to proceed.

2. Reasons to Use CountDownLatch

CountDownLatch can be immensely beneficial in various scenarios where thread synchronization is needed. Here are some key reasons to use CountDownLatch in your Java applications:

2.1 Coordinating a Start of a Set of Threads

Image

In a scenario where you have multiple threads that need to wait for each other to start simultaneously, CountDownLatch can be a good solution. For example, you might want to start multiple services at the same time and have them work together seamlessly.

import java.util.concurrent.CountDownLatch;

public class Service implements Runnable {
private final CountDownLatch latch;

public Service(CountDownLatch latch) {
this.latch = latch;
}

@Override
public void run() {
try {
System.out.println("Service " + Thread.currentThread().getName() + " is starting...");
Thread.sleep(2000); // Simulating service initialization
latch.countDown(); // Reducing count
System.out.println("Service " + Thread.currentThread().getName() + " has started.");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

public class Application {
public static void main(String[] args) {
int numberOfServices = 3;
CountDownLatch latch = new CountDownLatch(numberOfServices);

for (int i = 0; i < numberOfServices; i++) {
new Thread(new Service(latch)).start();
}

try {
latch.await(); // Waiting for all services to complete
System.out.println("All services are up, Application is starting now...");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

Output:

Service Thread-0 is starting...
Service Thread-1 is starting...
Service Thread-2 is starting...
Service Thread-0 has started.
Service Thread-1 has started.
Service Thread-2 has started.
All services are up, Application is starting now...

2.2 Dividing a Task into Several Parts

Image

Sometimes, a big task needs to be divided into smaller tasks that can be executed in parallel. Once all these sub-tasks are completed, the main thread can continue further processing. CountDownLatch makes this possible by allowing multiple threads to signal that their part of the work is done.

3. Using CountDownLatch for Multi-Phase Tasks

CountDownLatch is often used when you have multiple phases in a task, where each phase requires several threads to complete before moving on to the next phase. For example, in a simulation involving multiple processes, each phase could require all processes to synchronize at the end before moving on.

3.1 Multi-Phase Task Example

Consider a simulation where we need to perform multiple phases, and each phase involves several threads completing a task. Once all threads complete a phase, they can move to the next phase.

import java.util.concurrent.CountDownLatch;

public class PhaseTask implements Runnable {
private final CountDownLatch latch;
private final int phase;

public PhaseTask(CountDownLatch latch, int phase) {
this.latch = latch;
this.phase = phase;
}

@Override
public void run() {
try {
System.out.println("Thread " + Thread.currentThread().getName() + " is working on phase " + phase);
Thread.sleep(1000); // Simulating task execution
latch.countDown();
System.out.println("Thread " + Thread.currentThread().getName() + " completed phase " + phase);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

public class MultiPhaseApplication {
public static void main(String[] args) throws InterruptedException {
int phases = 3;
int threadsPerPhase = 5;

for (int phase = 1; phase <= phases; phase++) {
CountDownLatch latch = new CountDownLatch(threadsPerPhase);
for (int i = 0; i < threadsPerPhase; i++) {
new Thread(new PhaseTask(latch, phase)).start();
}
latch.await(); // Wait for all threads to complete the phase
System.out.println("Phase " + phase + " completed. Moving to next phase...");
}

System.out.println("All phases are completed.");
}
}

Output:

Thread Thread-0 is working on phase 1
...
Phase 1 completed. Moving to next phase...
...
All phases are completed.

3.2 Advantages of Using CountDownLatch

  • Simplicity: CountDownLatch offers a straightforward mechanism to synchronize threads.
  • Reusability: It can be used for multiple threads and in various situations, from waiting for services to start to completing phases in complex simulations.
  • Reliability: With a well-defined lifecycle and clear operations, CountDownLatch minimizes the risks of concurrency bugs.

4. Conclusion

CountDownLatch is a powerful utility in Java’s concurrency library, helping developers handle complex synchronization scenarios. By coordinating multiple threads efficiently, it simplifies code and improves reliability. Whether you need to manage service startups, divide tasks into parts, or synchronize multi-phase tasks, CountDownLatch is a robust choice.

If you have any questions or thoughts, feel free to leave a comment below!

Read more at : Using CountDownLatch in Java: A Deep Dive with Code Examples and Demos