Java Concurrency: Count Down Latches

Hello, readers, and welcome to yet another blog in the Java Concurrency series. Today, we are going to look at the CountDownLatch class in Java, what it is, and how to use it. So, let’s dive straight into it.

CountDownLatch in Java

Sometimes, we have a need to start our application only when a particular set of tasks are complete. These tasks might be running in parallel and getting completed together or at different times. Then, how do we tell our other threads that all the tasks are completed? How do we keep track of which tasks are complete and which are not? CountDownLatch is a class just for that.

We can define a CountDownLatch in our program as a class that keeps a counter with itself. The counter’s starting point is the number of threads that we need to wait for before we can notify other threads that they can start working. For example, if we need to wait for 5 tasks to be completed before other threads can start working, then the starting point for CountDownLatch will be 5.

When a thread finishes its task, it can just call CountDownLatch’s  countDown() method to let it know that the task is finished. countDown() decrements the starting point, or the count, by 1. So, when the count reaches 0, the Latch knows that all the threads have finished their tasks, and the waiting threads can now proceed.

The  await() method is a blocking method of CountDownLatch, which blocks until the count down reaches to zero, after which the await() method returns immediately. Let us look at an example code.

import java.util.concurrent.CountDownLatch;
public class CountDownLatchDemo {
private static final CountDownLatch COUNT_DOWN_LATCH = new CountDownLatch(5);
public static void main(String[] args) {
Thread run1 = new Thread(() -> {
System.out.println(“Doing some work..”);
try {
Thread.sleep(2000);
COUNT_DOWN_LATCH.countDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
});
Thread run2 = new Thread(() -> {
System.out.println(“Doing some work..”);
try {
Thread.sleep(2000);
COUNT_DOWN_LATCH.countDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
});
Thread run3 = new Thread(() -> {
System.out.println(“Doing some work..”);
try {
Thread.sleep(2000);
COUNT_DOWN_LATCH.countDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
});
Thread run4 = new Thread(() -> {
System.out.println(“Doing some work..”);
try {
Thread.sleep(2000);
COUNT_DOWN_LATCH.countDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
});
Thread run5 = new Thread(() -> {
System.out.println(“Doing some work..”);
try {
Thread.sleep(3000);
COUNT_DOWN_LATCH.countDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
});
run1.start();
run2.start();
run3.start();
run4.start();
run5.start();
try {
COUNT_DOWN_LATCH.await();
} catch (InterruptedException e) {
//Handle when a thread gets interrupted.
}
System.out.println(“All tasks have finished..”);
}
}

In the above code, we have defined a COUNT_DOWN_LATCH with starting point of 5, which means that our aim is to wait for 5 threads to be completed before executing our normal flow. Then, in the main method, we have started 5 threads, all doing some work and calling countDown() when the work has finished.

Notice here, that we do not need to worry about making COUNT_DOWN_LATCH synchronized, or thread-safe, as the internal implementation of CountDownLatch class is already synchronized.

We call the await() method of CountDownLatch to wait till the counter reaches 0, and then we execute our normal code flow.