What is the difference between CyclicBarrier and CountDownLatch in Java?

Thomas 124 Published: 08/23/2024

What is the difference between CyclicBarrier and CountDownLatch in Java?

In Java, CyclicBarrier and CountDownLatch are both synchronization tools used to coordinate threads, but they serve different purposes.

CountDownLatch

A CountDownLatch is a synchronization aid that allows one or more threads to wait at a single point until other threads have completed their work. It's commonly used in scenarios where you need to ensure that a set of tasks completes before proceeding with the next step.

Here's how it works:

Create a CountDownLatch instance, specifying the number of "counts" or "permits" needed. Call countDown() when each task completes its work, decrementing the count by 1. The waiting threads can then call await() to block until the count reaches zero.

Example: Imagine a batch processing system where multiple tasks need to complete before moving on to the next step. You can create a CountDownLatch with an initial count equal to the number of tasks, and have each task decrement the count when it completes. When all tasks have completed (i.e., the count reaches zero), the waiting threads will be released.

CyclicBarrier

A CyclicBarrier is a synchronization aid that allows a set of threads to wait at a barrier until other threads in the same group have reached the barrier. Unlike CountDownLatch, it's designed for scenarios where you need to coordinate multiple threads that form a group or team, and each member needs to reach a specific point before proceeding.

Here's how it works:

Create a CyclicBarrier instance, specifying the number of "parties" or "threads" in the group. Each thread calls await() at the barrier, which blocks until all threads in the same party have reached the barrier (i.e., called await()). Once all parties have reached the barrier, the waiting threads are released.

Example: Picture a scenario where multiple workers need to process tasks in parallel, and you want to ensure that all workers have completed their tasks before proceeding with the next set of tasks. You can create a CyclicBarrier with an initial number of parties equal to the number of workers, and have each worker call await() at the barrier. When all workers have reached the barrier (i.e., called await()), the waiting threads will be released.

In summary:

Use CountDownLatch when you need to ensure that a set of tasks completes before proceeding with the next step. Use CyclicBarrier when you need to coordinate multiple threads that form a group or team, and each member needs to reach a specific point before proceeding.

While both tools are used for synchronization, they serve distinct purposes. Understanding the differences between them will help you choose the right tool for your Java concurrency needs.

Java countdownlatch example

Here is an example of using a CountdownLatch in Java:

import java.util.concurrent.CountDownLatch;

public class Main {

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

CountDownLatch latch = new CountDownLatch(5);

for (int i = 0; i < 5; i++) {

new Thread(() -> {

try {

// do some work

System.out.println("Thread " + Thread.currentThread().getId() + " is waiting");

Thread.sleep(10000);

System.out.println("Thread " + Thread.currentThread().getId() + " is finished");

latch.countDown();

} catch (InterruptedException e) {

throw new RuntimeException(e);

}

}).start();

}

// Main thread waits for all threads to finish

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

latch.await();

System.out.println("All threads have finished");

}

}

In this example, a CountdownLatch is used to control the flow of execution in a program. A CountdownLatch represents a countdown that can be incremented by 1 multiple times and decremented until it reaches zero.

When the main thread starts waiting, all the other threads (5 in this case) are allowed to run their tasks and finish. After all threads have finished their tasks, they decrement the latch's count by calling countDown(). Once all threads have finished, the latch's count reaches zero, allowing the main thread to continue with its execution.

The await() method blocks until the count reaches zero, which means that the main thread will not continue until all other threads have finished. This is useful for ensuring that a set of tasks or operations are completed before moving on to the next step.

Here's how the code works:

The program starts by creating a new CountDownLatch object and setting its count to 5. Five new threads are created, each executing the same task: doing some work (in this case, sleeping for 10 seconds) and then decrementing the latch count when finished. The main thread waits until all five threads have finished by calling await() on the latch object. This blocks the main thread until all other threads have finished their tasks and decremented the latch count to zero.

Here's what you would see in the console output:

Main thread starts waiting

Thread 1 is waiting

Thread 2 is waiting

Thread 3 is waiting

Thread 4 is waiting

Thread 5 is waiting

Thread 1 is finished

Thread 2 is finished

Thread 3 is finished

Thread 4 is finished

Thread 5 is finished

All threads have finished