CountDownLatch in Java

Introduction

A CountDownLatch in Java is a synchronization aid which allows one or more threads to wait (block) until something else happens (or gets completed). In this post, let us learn about CountDownLatch in Java.

What is CountDownLatch in Java

As per the Javadoc of CountDownLatch,

A CountDownLatch is a synchronization aid that allows one or more threads to wait until a set of operations being performed in other threads completes.

We may have a situation when a thread (say T1) has to wait for some other thread (say T2) to finish doing something before T1 can do something else. In such scenarios, we can use a CountDownLatch for communicating between the two threads.

Note: You can extend this to any number of threads as well.

As shown below, thread T1 executes some work (function f1() here). But before it can start f4(), it has to ensure thread T2 has completed f2 and f3. Thus, it has to wait for T2 before starting f4.

CountDownLatch Thread Waiting
CountDownLatch Thread Waiting example

We have used a CountDownLatch to enable the communication and wait between threads. Let us now understand how a CountDownLatch works and how we can use it.

Initializing a CountDownLatch

We first create a CountDownLatch, initialized with a given count (1 in our example). This count determines how many threads on which a thread will wait on i.e., how many times the latch will be counted down

Awaiting and counting down on a CountDownLatch

A thread will wait on a CountDownLatch by calling its await() method. Calling this will block the thread until the count of the CountDownLatch reaches zero. 

The count will reduce by one when we call the CountDownLatch’s countDown() method. The other thread(s) which are now blocking a thread (or multiple threads) will have to call the countDown method (thus reducing the count). Once the count reaches zero, all waiting threads will be released and can be scheduled by the scheduler for running. Once the count reaches zero, all subsequent invocations of await() will return immediately.

In the shown example, we initialize the CountDownLatch with count as 1. Once thread T1 completes f1, it will call the await() method on the CountDownLatch. This will block thread T1 from running. It can resume back only when the CountDownLatch has been countdown to zero.

This happens from T2 i.e., once thread T2 has completed f2 and f3, it will call countDown() on the CountDownLatch causing the count to become 0. This will release thread T1 (the only waiting thread) and can continue to execute f4.

A CountDownLatch initialized with a count of one can act as a simple on/off gate. All threads wait at the gate after invoking await and the gate will be opened when countDown is invoked by other thread. When we have a latch initialized to N, to unlock the waiting thread(s), N other threads have to invoke countDown. We will see examples for both.

Note: Once a CountDown latch reaches a count of 0, we cannot reset it. If we need such a resetting latch, we can use a CyclicBarrier.

On/Off CountDownLatch example

In this example, we will see the code for the example we have seen. The CountDownLatch acts as a on/off latch.

Let us create two Runnable classes which we will use to create the two threads. Shown below is the code for first Runnable.

private static class Runnable1 implements Runnable {
    private final CountDownLatch latch;

    private Runnable1(CountDownLatch latch) {
        this.latch = latch;
    }

    @Override
    public void run() {
        f1();
        // (A)Waiting on the countDown latch
        try {
            printMessage("Waiting on the latch");
            latch.await();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        printMessage("The latch is now open. Proceeding to execute f4");
        f4();
    }

    private void f1() {
        printMessage("Running f1()");
    }

    private void f4() {
        printMessage("Running f4()");
    }
}
private static void printMessage(String message) {
    System.out.printf("[%s] %s\n", Thread.currentThread().getName(), message);
}

It has a CountDownLatch instance variable. In the run method, it first calls the f1 function and awaits on the CountDownLatch. Calling the await method can throw an InterruptedException i.e., the waiting thread could be interrupted. If that happens, we wrap it in a RuntimeException and throw it back.

Once the latch is countdown by the other thread (we will see this shortly), the count of the latch will become zero. This will unblock or release the waiting thread and it proceeds to execute the remainder of the code (calling f4).

To prepend the thread name to the printed message, we have a utility method, printMessage.

We have the code for the second Runnable here.

private static class Runnable2 implements Runnable {
    private final CountDownLatch latch;

    private Runnable2(CountDownLatch latch) {
        this.latch = latch;
    }

    @Override
    public void run() {
        f2();
        f3();
        printMessage("f2 and f3 have been completed. Counting the latch down");
        latch.countDown();
    }

    private void f2() {
        printMessage("Running f2()");
    }

    private void f3() {
        printMessage("Running f3()");
    }
}

It calls f2 and f3 and calls countDown on the latch.

On/Off Latch in action

Let us now run this code. 

public static void main(String[] args) {
    CountDownLatch latch = new CountDownLatch(1);
    Runnable1 runnable1 = new Runnable1(latch);
    Runnable2 runnable2 = new Runnable2(latch);

    Thread t1 = new Thread(runnable1);
    Thread t2 = new Thread(runnable2);
    t1.start();
    t2.start();
}

We create a CountDown latch instance with count set to 1. Then we create instances of the runnable passing this latch. Finally, we create two threads passing the runnables and start the thread.

One possible sequence of output is shown below.
[Thread-0] Running f1()
[Thread-1] Running f2()
[Thread-0] Waiting on the latch
[Thread-1] Running f3()
[Thread-1] f2 and f3 have been completed. Counting the latch down
[Thread-0] The latch is now open. Proceeding to execute f4
[Thread-0] Running f4()

The reason I said ‘possible sequence’ is, thread 1 and thread 2 can start executing f1 and f3, f4 in any order as there is no synchronization between them here. Hence, there can be changes in the order of messages executing f1, f3 and f4.

The thing to note here is once thread 1 (Thread-0) has completed running f1, it waits on the latch. The latch is countdown by thread 2 (Thread-1) after completing f2 and f3. Then, thread 1 (Thread-0) runs f4.

Waiting for N threads

Let us now look at the usage of CountDownLatch in Java where one thread waits for N threads to complete execution.

private static class MyRunnable implements Runnable {
    private final CountDownLatch doneSignal;
    private final Random random;

    MyRunnable(CountDownLatch doneSignal) {
        this.doneSignal = doneSignal;
        this.random = new Random();
    }

    public void run() {
        try {
            Thread.sleep(random.nextLong(500, 2000));
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        System.out.printf("Thread [%s] done executing. Counting down the latch\n", Thread.currentThread().getName());
        doneSignal.countDown();

    }
}

The MyRunnable class has a CountDownLatch and a Random instance. It just sleeps for a random number of seconds (from 0.5 – 2 seconds), prints a message and counts down the latch. Shown below is the main driver for the code.

public static void main(String[] args) throws InterruptedException {
    int N = 5;
    CountDownLatch doneSignal = new CountDownLatch(N);

    for (int i = 0; i < N; i++) {
        new Thread(new MyRunnable(doneSignal)).start();
    }
    System.out.println("Waiting for all threads to finish");
    doneSignal.await();
    System.out.println("All tasks completed");
}

We create a CountDownLatch with count as 5. We create 5 threads passing different runnable instances and start each of them and await on the latch. Once all threads have completed, the waiting thread (main thread) will be released and prints a completion message.

Running this, one possible sequence of output is,
Waiting for all threads to finish
Thread [Thread-4] done executing. Counting down the latch
Thread [Thread-1] done executing. Counting down the latch
Thread [Thread-3] done executing. Counting down the latch
Thread [Thread-0] done executing. Counting down the latch
Thread [Thread-2] done executing. Counting down the latch
All tasks completed

Note: Though the order of the thread’s execution might change, the main thread’s print message order (waiting for threads and then printing the completion message) won’t change.

Using two countdown latches

The Javadoc of CountDownLatch has an example where we use two latches. The scenario is similar to the previous code, but there is some initial setup (pre-work) required before starting the (worker) runnables i.e., the main thread has to do some work and will signal the worker threads to start. Hence, the worker runnables will be awaiting on a latch, which will be countdown by the main thread. Here’s the Runnable,

private static class MyRunnable implements Runnable {
    private final CountDownLatch startSignal;
    private final CountDownLatch doneSignal;
    private final Random random;

    MyRunnable(CountDownLatch startSignal, CountDownLatch doneSignal) {
        this.startSignal = startSignal;
        this.doneSignal = doneSignal;
        this.random = new Random();
    }

    public void run() {
        try {
            System.out.printf("Thread [%s] Waiting for the start signal\n", Thread.currentThread().getName());
            startSignal.await();
            Thread.sleep(random.nextLong(500, 2000));
        } catch (InterruptedException e) {
           throw new RuntimeException(e);
        }

        System.out.printf("Thread [%s] done executing. Counting down the latch\n", Thread.currentThread().getName());
        doneSignal.countDown();

    }
}

It has a startSignal and a doneSignal latch. Before starting the execution, the runnable (thread) will wait on the startSignal. In other words, only after the startSignal latch is countdown to zero it will begin the work. Here, as before, it just sleeps for a random period of time. After that, it prints a message and counts down the doneSignal.

Driver code for two countdown latches

The main driver code is shown below (this time using only 3 threads to keep the output simple).

We create two countdown latches (startSignal and doneSignal) and create and start the 3 threads.

public static void main(String[] args) throws InterruptedException {
    int N = 3;
    CountDownLatch startSignal = new CountDownLatch(1);
    CountDownLatch doneSignal = new CountDownLatch(N);

    for (int i = 0; i < N; i++) {
        new Thread(new MyRunnable(startSignal, doneSignal)).start();
    }

    System.out.println("Main thread doing some work");
    System.out.println("Signalling all threads to start");
    startSignal.countDown(); // let all threads proceed

    System.out.println("Waiting for all threads to finish");
    doneSignal.await();
    System.out.println("All tasks completed");
}

The main thread does some work (which is just printing a message here) and counts down the startSignal count down latch. This will release all waiting (worker) threads to proceed. Finally, as seen before, the main thread waits on the doneSignal latch (waiting for the worker threads to finish).

The output is,
Thread [Thread-0] Waiting for the start signal
Thread [Thread-2] Waiting for the start signal
Main thread doing some work
Thread [Thread-1] Waiting for the start signal
Signalling all threads to start
Waiting for all threads to finish
Thread [Thread-0] done executing. Counting down the latch
Thread [Thread-1] done executing. Counting down the latch
Thread [Thread-2] done executing. Counting down the latch
All tasks completed

Observation:

  • The worker threads have started and are waiting for the start signal from the main thread (startSignal latch).
  • Main thread does its work and signals (counts down) the startSignal latch and waits for the threads to finish (using doneSignal latch).
  • All worker threads are unblocked and proceed to do work. After it is done counts down the doneSignal latch.
  • Once all the doneSignal is counted down to zero, the main thread is now released and prints the final message.

Awaiting with timeout

As we have learnt, a thread awaiting on a countdown latch will continue to be blocked until some other thread(s) counts down the same latch to zero. Now what if that never happens? What if one or more threads fail in their execution and the countdown latch’s count never gets to zero? The thread(s) waiting on the latch will be blocked forever. 

To avoid that, we can use the overloaded await method which takes a timeout. The method signature is,

public boolean await(long timeout, TimeUnit unit)

It takes a long timeout and a TimeUnit. Thus, the await won’t block the thread forever. The thread will be eligible for scheduling when one of the below happens:

  • The current thread is interrupted – then it throws an InterruptedException.
  • The count reaches zero (then the method returns true).
  • When the timeout elapses (then the method returns false).

In this example, I’ll use awaiting with timeout when using a countdown latch with count as 1. The thread will use the below runnable which counts down the latch after 5 seconds.

private static class MyRunnable implements Runnable {
    private final CountDownLatch latch;

    private MyRunnable(CountDownLatch latch) {
        this.latch = latch;
    }

    @Override
    public void run() {
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        System.out.println("Counting down");
        latch.countDown();
    }
}

The main driver code is,

public static void main(String[] args) throws InterruptedException {
    CountDownLatch latch = new CountDownLatch(1);
    new Thread(new MyRunnable(latch)).start();

    while (true) {
        System.out.println("Awaiting");
        boolean result = latch.await(1, TimeUnit.SECONDS);
        if (result) {
            System.out.println("Latch is released");
            break;
        } else {
            System.out.println("Latch is not open yet..");
        }
    }
}

In an infinite loop, we start the await. Each await will happen for 1 second. If we get back a true, it means the latch is released. If not, we print a message and go back to waiting on the latch again (for another 1 second).

This prints,
Awaiting
Latch is not open yet..
Awaiting
Latch is not open yet..
Awaiting
Latch is not open yet..
Awaiting
Latch is not open yet..
Awaiting
Counting down
Latch is released

The penultimate message is printed by the runnable thread before calling countDown on the latch and the rest by the main thread.

Note: Though I’ve used an infinite loop for demonstrating the await with timeout on a countdown latch here, in reality, if the latch isn’t counted down by the expected time, we would no longer await and take some other action.

Other methods on CountDownLatch

The countdown latch class has two methods which we haven’t seen yet – getCount and it also implements toString.

The getCount method returns the current count of the countdown latch. It will be useful for debugging and testing purposes.

The toString prints the state of the latch (which is the count).
CountDownLatch latch = new CountDownLatch(3);
System.out.println(latch.getCount());
System.out.println(latch);

Prints,

3
java.util.concurrent.CountDownLatch@2f92e0f4[Count = 3]

Conclusion

This brings us to the end of this post on CountDownLatch in Java 8 with examples. You might want to take a look at other important classes and interfaces in Java.

Leave a Reply