← Back to Multithreading Course

JAVA MULTITHREADING · CLASS 23

Coordinating Threads with CountDownLatch

Sometimes, one thread needs to wait until several other threads finish their work. Java provides CountDownLatch to help us coordinate such situations.

1. Understanding the Problem

Imagine that you are organizing an event. Before the event can begin, three different teams must finish their preparations:

  • Team 1 prepares the stage.
  • Team 2 arranges the chairs.
  • Team 3 prepares the sound system.

The event should start only after all three teams have finished their work.

You do not want to keep checking whether each team has finished. You simply want to wait until all three teams report that they are done.

This is exactly the kind of situation where CountDownLatch can help.

2. What Is CountDownLatch?

CountDownLatch is a Java utility that allows one or more threads to wait until a counter reaches zero.

We create a CountDownLatch with an initial count. Whenever a task finishes, it decreases that count.

Once the count becomes zero, any threads waiting on the latch are allowed to continue.

Let's understand its two important methods.

countDown()

This method decreases the latch counter by one.

For example, if the initial count is 3, calling countDown() changes it to 2.

await()

This method makes the current thread wait until the latch counter reaches zero.

If the counter is already zero, the thread does not need to wait and can continue immediately.

Here is a simple example of how the counter works:

CountDownLatch latch = new CountDownLatch(3);

latch.countDown(); // Count becomes 2
latch.countDown(); // Count becomes 1
latch.countDown(); // Count becomes 0

latch.await();     // Continues immediately because count is 0

Notice that await() does not decrease the counter. It only waits for the counter to become zero.

3. Let's Write Our First Program

Now let's create a practical example.

We will create three worker threads. Each worker will perform some work. The main thread will wait until all three workers have completed their work.

First, let's look at the complete program.

import java.util.concurrent.CountDownLatch;

public class CountDownLatchExample {

    public static void main(String[] args)
            throws InterruptedException {

        CountDownLatch latch = new CountDownLatch(3);

        for (int i = 1; i <= 3; i++) {

            final int workerNumber = i;

            Thread worker = new Thread(() -> {

                try {

                    System.out.println(
                        "Worker " + workerNumber + " started"
                    );

                    Thread.sleep(2000);

                    System.out.println(
                        "Worker " + workerNumber + " completed"
                    );

                } catch (InterruptedException e) {

                    Thread.currentThread().interrupt();

                } finally {

                    latch.countDown();
                }

            });

            worker.start();
        }

        System.out.println("Main thread is waiting...");

        latch.await();

        System.out.println("All workers completed!");
    }
}

4. Understanding the Program Step by Step

Step 1: Create the latch

CountDownLatch latch = new CountDownLatch(3);

We create a CountDownLatch with an initial count of 3.

This means the latch needs three countdown operations before its counter reaches zero.

Step 2: Start three worker threads

for (int i = 1; i <= 3; i++) {
    // Create and start a worker thread
}

We create three separate threads. Each thread performs its own work independently.

Step 3: Perform the work

System.out.println("Worker " + workerNumber + " started");

Thread.sleep(2000);

System.out.println("Worker " + workerNumber + " completed");

Each worker prints a starting message, waits for two seconds to simulate some work, and then prints a completion message.

Remember, sleep() is only being used to simulate work in this example.

Step 4: Decrease the counter

finally {
    latch.countDown();
}

Once a worker finishes, it calls countDown().

We have placed this call inside the finally block. This means the countdown happens even if the worker is interrupted while performing its work.

The counter changes like this:

  • Initially: 3
  • After the first worker finishes: 2
  • After the second worker finishes: 1
  • After the third worker finishes: 0

Step 5: Make the main thread wait

System.out.println("Main thread is waiting...");

latch.await();

System.out.println("All workers completed!");

The main thread calls await().

It cannot move to the next statement until the latch counter reaches zero.

Once all three workers have called countDown(), the counter becomes zero. The main thread can then continue.

5. Understanding the Execution Flow

Let's visualize what happens in our program.

Main Thread
    |
    | Creates CountDownLatch(3)
    |
    | Starts Worker 1
    | Starts Worker 2
    | Starts Worker 3
    |
    | Calls await()
    |
    | Waits...
    |
    |<------------------------------->
    |                                 |
    |                         Worker 1 completes
    |                         countDown(): 3 -> 2
    |
    |                         Worker 2 completes
    |                         countDown(): 2 -> 1
    |
    |                         Worker 3 completes
    |                         countDown(): 1 -> 0
    |
    |<-------------------------------->
    |
    | Continues execution
    |
    Prints "All workers completed!"

The important point is that the main thread does not need to check the status of individual workers.

It simply waits on the latch. The latch takes care of allowing it to continue when the counter reaches zero.

6. Important Things to Remember

  • CountDownLatch is part of Java's java.util.concurrent package.
  • countDown() decreases the counter by one.
  • await() makes the current thread wait until the counter reaches zero.
  • Multiple threads can call await() on the same latch. They can all continue once the counter reaches zero.
  • CountDownLatch is thread-safe. Multiple threads can safely call its methods.
  • A CountDownLatch cannot be reset after its counter reaches zero. If you need another countdown cycle, create a new latch.

What happens if the count never reaches zero?

Any thread waiting on await() will continue waiting until the count reaches zero or the waiting thread is interrupted.

Also, await() can throw InterruptedException. That is why our main method declares throws InterruptedException.

7. When Should We Use CountDownLatch?

CountDownLatch is useful whenever one thread needs to wait for a specific number of events or tasks to finish.

For example:

  • Wait for multiple services to finish initialization before starting an application.
  • Wait for multiple files to finish processing before generating a final report.
  • Wait for multiple worker threads to complete before displaying the final result.

Think of CountDownLatch as a simple countdown. When the count reaches zero, the waiting threads can move forward.

Test Your Understanding

Let's see how well you understood this class!

Question 1: What is the primary purpose of CountDownLatch?

Question 2: What does countDown() do?

Question 3: What happens when a thread calls await() while the counter is greater than zero?

Question 4: If a CountDownLatch starts with a count of 3, how many countDown() calls are needed to reach zero?

Question 5: Can we reset a CountDownLatch after its counter reaches zero?

Class Summary

Today, we learned how CountDownLatch helps coordinate multiple threads.

  • CountDownLatch starts with an initial counter value.
  • countDown() decreases the counter by one.
  • await() makes a thread wait until the counter reaches zero.
  • Multiple threads can wait on the same latch.
  • Once the counter reaches zero, it cannot be reset.

The key takeaway: CountDownLatch helps us make one or more threads wait until a specific number of tasks are completed.

Coming Up Next: Class 24

Coordinating Threads with CyclicBarrier

In this class, we will learn about another coordination mechanism called CyclicBarrier.

Unlike CountDownLatch, which lets threads wait for a countdown to finish, CyclicBarrier allows a group of threads to wait for one another at a common point before continuing together.

Let's understand how it works in our next class!

0% Completed

You have completed 23 out of 46 classes.