Java Concurrency and Multithreading

CountDownLatch in Java: A Comprehensive Guide

1. Introduction

The CountDownLatch class is a powerful concurrency construct provided by Java. Its purpose is to allow one or more threads to wait until a given set of operations performed by other threads completes. Essentially, it acts as a synchronization aid.

2. Basics of CountDownLatch

  • Initialization:
    • A CountDownLatch is initialized with a specific count (usually the number of threads we want to wait for).
    • This count represents the number of times the countDown() method must be called before the waiting threads are released.
  • Decrementing the Count:
    • Threads that complete their work call the countDown() method.
    • Each call decrements the internal counter.
    • When the counter reaches zero, the waiting threads are unblocked.
  • Waiting Threads:
    • Threads waiting for the counter to reach zero call one of the await() methods.
    • The calling thread blocks until the counter becomes zero or until it’s interrupted.

3. Practical Examples

Example 1: Waiting for a Pool of Threads to Complete

Let’s create a scenario where we have multiple pizza makers (threads) preparing pizzas. We’ll use a CountDownLatch to ensure that the main thread waits until all pizza makers finish making their pizzas.

import java.util.*;
import java.util.concurrent.CountDownLatch;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class PizzaMakerDemo {
    public static void main(String[] args) throws InterruptedException {
        List<String> outputScraper = Collections.synchronizedList(new ArrayList<>());
        int numPizzaMakers = 5; // Number of pizza makers

        // Initialize the CountDownLatch with the number of pizza makers
        CountDownLatch countDownLatch = new CountDownLatch(numPizzaMakers);

        // Create pizza maker threads
        List<Thread> pizzaMakers = Stream.generate(() -> new Thread(new PizzaMaker(outputScraper, countDownLatch)))
                .limit(numPizzaMakers)
                .collect(Collectors.toList());

        // Start the pizza maker threads
        pizzaMakers.forEach(Thread::start);

        // Wait for all pizza makers to finish
        countDownLatch.await();

        // Main thread continues after all pizzas are made
        outputScraper.add("All pizzas are ready!");

        // Print the output
        outputScraper.forEach(System.out::println);
    }
}

class PizzaMaker implements Runnable {
    private final List<String> outputScraper;
    private final CountDownLatch countDownLatch;

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

    @Override
    public void run() {
        // Simulate pizza-making process
        try {
            Thread.sleep(2000); // Pretend to make a pizza
            outputScraper.add("Pizza made!");
            countDownLatch.countDown(); // Signal completion
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

Example 2: A Pool of Threads Waiting to Begin

If we start thousands of threads instead of just five, some may finish processing before others even start. To reproduce concurrency problems, we need all threads to run in parallel. Let’s modify the CountDownLatch behavior:

// Create a CountDownLatch with an initial count of 1
CountDownLatch startLatch = new CountDownLatch(1);

// In each worker thread, wait for the start signal
// (before doing any actual work)
startLatch.await();

// Perform the actual work here
// ...

// In the main thread, release the start signal
startLatch.countDown();

4. Conclusion

The CountDownLatch is a versatile tool for coordinating threads and ensuring synchronization in concurrent applications. Whether you’re dealing with parallel processing, testing, or other scenarios, it empowers you to manage thread interactions effectively.

Remember to use it wisely, and happy coding! 🚀

For more information, check out these resources:

Avatar

Neelabh

About Author

As Neelabh Singh, I am a Senior Software Engineer with 6.6 years of experience, specializing in Java technologies, Microservices, AWS, Algorithms, and Data Structures. I am also a technology blogger and an active participant in several online coding communities.

You may also like

Blog Java Java 8 Features

Avoid NullPointerException in Java with Optional: A Comprehensive Guide

Are you tired of dealing with avoid NullPointerExceptions(NPEs) in your Java code? Look no further than the Optional class introduced
Blog Java Java 8 Features

Unlocking the Power of Java 8 Streams: A Guide to Efficient Data Processing

What are Java 8 Streams? At its core, a stream in Java 8 is a sequence of elements that facilitates