What is the difference between CountDownLatch and barrier in Java?

Mason 106 Published: 09/08/2024

What is the difference between CountDownLatch and barrier in Java?

The CountDownLatch and CyclicBarrier are both part of the Java concurrency API, designed to help manage concurrent execution of threads. While they share some similarities, they serve different purposes and have distinct use cases.

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. It's commonly used when you need to ensure that a certain number of threads have finished their tasks before proceeding with the next step.

Here are key characteristics:

One-way: A CountDownLatch can be counted down only once, and once it reaches zero, it cannot be incremented again. Fixed count: The latch is initialized with a specific count (i.e., the number of threads waiting to be released). Release all or none: When one thread calls countDown(), it releases all threads waiting on the latch.

Use cases:

Synchronization: Ensure that a set of operations completes before moving forward. Thread coordination: Coordinate multiple threads performing distinct tasks, where one task depends on others completing first.

CyclicBarrier

A CyclicBarrier is a synchronization aid that allows a set of threads to wait at a barrier until all participating threads have reached the barrier. It's designed for scenarios where a group of threads need to wait for each other to reach a specific point, and then continue as a synchronized unit.

Key characteristics:

Cyclical: A CyclicBarrier resets itself after all threads have passed it once. Variable count: The barrier can be initialized with any number of participating threads. Release all: When one thread calls await(), it releases all threads waiting at the barrier.

Use cases:

Thread groups: Coordinate a group of threads that need to wait for each other before continuing. Phased computations: Implement a phased computation where multiple threads work together, and each phase requires all threads to complete their tasks before proceeding.

In summary:

CountDownLatch is used when you need to ensure a specific number of threads have finished their tasks before proceeding with the next step. CyclicBarrier is used when you need to coordinate a group of threads that need to wait for each other before continuing as a synchronized unit.

While both classes can be used for thread coordination and synchronization, the main difference lies in the purpose and behavior: one-way vs cyclical, fixed count vs variable count, and release-all-or-none vs release-all.

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