Guide to CountDownLatch in Java

1. Introduction

In this article, we’ll give a guide to the CountDownLatch class and demonstrate how it can be used in a few practical examples.

Essentially, by using a CountDownLatch we can cause a thread to block until other threads have completed a given task.

2. Usage in Concurrent Programming

Simply put, a CountDownLatch has a counter field, which you can decrement as we require. We can then use it to block a calling thread until it’s been counted down to zero.

If we were doing some parallel processing, we could instantiate the CountDownLatch with the same value for the counter as a number of threads we want to work across. Then, we could just call countdown() after each thread finishes, guaranteeing that a dependent thread calling await() will block until the worker threads are finished.

3. Waiting for a Pool of Threads to Complete

Let’s try out this pattern by creating a Worker and using a CountDownLatch field to signal when it has completed:

public class Worker implements Runnable {
    private List<String> outputScraper;
    private CountDownLatch countDownLatch;

    public Worker(List<String> outputScraper, CountDownLatch countDownLatch) {
        this.outputScraper = outputScraper;
        this.countDownLatch = countDownLatch;
    }

    @Override
    public void run() {
        doSomeWork();
        outputScraper.add("Counted down");
        countDownLatch.countDown();
    }
}

Then, let’s create a test in order to prove that we can get a CountDownLatch to wait for the Worker instances to complete:

@Test
public void whenParallelProcessing_thenMainThreadWillBlockUntilCompletion()
  throws InterruptedException {

    List<String> outputScraper = Collections.synchronizedList(new ArrayList<>());
    CountDownLatch countDownLatch = new CountDownLatch(5);
    List<Thread> workers = Stream
      .generate(() -> new Thread(new Worker(outputScraper, countDownLatch)))
      .limit(5)
      .collect(toList());

      workers.forEach(Thread::start);
      countDownLatch.await(); 
      outputScraper.add("Latch released");

      assertThat(outputScraper)
        .containsExactly(
          "Counted down",
          "Counted down",
          "Counted down",
          "Counted down",
          "Counted down",
          "Latch released"
        );
    }

Naturally “Latch released” will always be the last output – as it’s dependant on the CountDownLatch releasing.

Note that if we didn’t call await(), we wouldn’t be able to guarantee the ordering of the execution of the threads, so the test would randomly fail.

4. A Pool of Threads Waiting to Begin

If we took the previous example, but this time started thousands of threads instead of five, it’s likely that many of the earlier ones will have finished processing before we have even called start() on the later ones. This could make it difficult to try and reproduce a concurrency problem, as we wouldn’t be able to get all our threads to run in parallel.

To get around this, let’s get the CountdownLatch to work differently than in the previous example. Instead of blocking a parent thread until some child threads have finished, we can block each child thread until all the others have started.

Let’s modify our run() method so it blocks before processing:

public class WaitingWorker implements Runnable {

    private List<String> outputScraper;
    private CountDownLatch readyThreadCounter;
    private CountDownLatch callingThreadBlocker;
    private CountDownLatch completedThreadCounter;

    public WaitingWorker(
      List<String> outputScraper,
      CountDownLatch readyThreadCounter,
      CountDownLatch callingThreadBlocker,
      CountDownLatch completedThreadCounter) {

        this.outputScraper = outputScraper;
        this.readyThreadCounter = readyThreadCounter;
        this.callingThreadBlocker = callingThreadBlocker;
        this.completedThreadCounter = completedThreadCounter;
    }

    @Override
    public void run() {
        readyThreadCounter.countDown();
        try {
            callingThreadBlocker.await();
            doSomeWork();
            outputScraper.add("Counted down");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            completedThreadCounter.countDown();
        }
    }
}

Now, let’s modify our test so it blocks until all the Workers have started, unblocks the Workers, and then blocks until the Workers have finished:

@Test
public void whenDoingLotsOfThreadsInParallel_thenStartThemAtTheSameTime()
 throws InterruptedException {
 
    List<String> outputScraper = Collections.synchronizedList(new ArrayList<>());
    CountDownLatch readyThreadCounter = new CountDownLatch(5);
    CountDownLatch callingThreadBlocker = new CountDownLatch(1);
    CountDownLatch completedThreadCounter = new CountDownLatch(5);
    List<Thread> workers = Stream
      .generate(() -> new Thread(new WaitingWorker(
        outputScraper, readyThreadCounter, callingThreadBlocker, completedThreadCounter)))
      .limit(5)
      .collect(toList());

    workers.forEach(Thread::start);
    readyThreadCounter.await(); 
    outputScraper.add("Workers ready");
    callingThreadBlocker.countDown(); 
    completedThreadCounter.await(); 
    outputScraper.add("Workers complete");

    assertThat(outputScraper)
      .containsExactly(
        "Workers ready",
        "Counted down",
        "Counted down",
        "Counted down",
        "Counted down",
        "Counted down",
        "Workers complete"
      );
}

This pattern is really useful for trying to reproduce concurrency bugs, as can be used to force thousands of threads to try and perform some logic in parallel.

5. Terminating a CountdownLatch Early

Sometimes, we may run into a situation where the Workers terminate in error before counting down the CountDownLatch. This could result in it never reaching zero and await() never terminating:

@Override
public void run() {
    if (true) {
        throw new RuntimeException("Oh dear, I'm a BrokenWorker");
    }
    countDownLatch.countDown();
    outputScraper.add("Counted down");
}

Let’s modify our earlier test to use a BrokenWorker, in order to show how await() will block forever:

@Test
public void whenFailingToParallelProcess_thenMainThreadShouldGetNotGetStuck()
  throws InterruptedException {
 
    List<String> outputScraper = Collections.synchronizedList(new ArrayList<>());
    CountDownLatch countDownLatch = new CountDownLatch(5);
    List<Thread> workers = Stream
      .generate(() -> new Thread(new BrokenWorker(outputScraper, countDownLatch)))
      .limit(5)
      .collect(toList());

    workers.forEach(Thread::start);
    countDownLatch.await();
}

Clearly, this is not the behavior we want – it would be much better for the application to continue than infinitely block.

To get around this, let’s add a timeout argument to our call to await().

boolean completed = countDownLatch.await(3L, TimeUnit.SECONDS);
assertThat(completed).isFalse();

As we can see, the test will eventually time out and await() will return false.

6. Conclusion

In this quick guide, we’ve demonstrated how we can use a CountDownLatch in order to block a thread until other threads have finished some processing.

We’ve also shown how it can be used to help debug concurrency issues by making sure threads run in parallel.

The implementation of these examples can be found over on GitHub; this is a Maven-based project, so should be easy to run as is.

Related posts:

Java Program to Find Strongly Connected Components in Graphs
Spring Autowiring of Generic Types
Java Program to Implement RoleList API
Biểu thức Lambda trong Java 8 – Lambda Expressions
Retrieve User Information in Spring Security
Java Program to Implement Slicker Algorithm that avoids Triangulation to Find Area of a Polygon
Introduction to PCollections
Java Program to Implement the MD5 Algorithm
Spring Boot with Multiple SQL Import Files
JUnit5 Programmatic Extension Registration with @RegisterExtension
Java Program to Implement Aho-Corasick Algorithm for String Matching
Create a Custom Exception in Java
Easy Ways to Write a Java InputStream to an OutputStream
Java Program to Implement Miller Rabin Primality Test Algorithm
Finding Max/Min of a List or Collection
Enum trong java
Convert Hex to ASCII in Java
Spring Boot - Application Properties
Java Program to Implement the Schonhage-Strassen Algorithm for Multiplication of Two Numbers
Java Web Services – Jersey JAX-RS – REST và sử dụng REST API testing tools với Postman
Java Program to Print only Odd Numbered Levels of a Tree
Tạo ứng dụng Java RESTful Client với thư viện OkHttp
Flattening Nested Collections in Java
Java Program to Implement Floyd-Warshall Algorithm
Guide to @ConfigurationProperties in Spring Boot
Java Program to Implement Merge Sort on n Numbers Without tail-recursion
Java Program to Implement Rope
Jackson – Unmarshall to Collection/Array
4 tính chất của lập trình hướng đối tượng trong Java
REST Web service: Tạo ứng dụng Java RESTful Client với Jersey Client 2.x
Java Program to Implement Binary Tree
Limiting Query Results with JPA and Spring Data JPA