What is the difference between CyclicBarrier and CountDownLatch in Java?

Octavia 186 Published: 08/19/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 increment

I'll respond in English for this special occasion!

The CountDownLatch class in Java is a synchronization tool that allows one or more threads to wait at a specific point until a set of operations being performed in other threads has completed.

To increment the count of a CountDownLatch, you can simply call its countDown() method. This method decrements the latch's internal counter by 1, indicating that one operation has been completed.

Here's an example of how to use CountDownLatch:

import java.util.concurrent.CountDownLatch;

public class Main {

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

// Create a CountDownLatch with a count of 3

final CountDownLatch latch = new CountDownLatch(3);

// Start three threads, each waiting for the latch to be counted down to 0

Thread t1 = new Thread(() -> {

try {

latch.await(); // Wait until the latch is counted down to 0

System.out.println("Thread 1: Latch is counted down to 0");

} catch (InterruptedException e) {

throw e;

}

});

t1.start();

Thread t2 = new Thread(() -> {

try {

// Simulate some operation taking place

Thread.sleep(2000);

System.out.println("Thread 2: Operation completed");

latch.countDown(); // Decrement the count of the latch by 1

System.out.println("Thread 2: Counted down");

} catch (InterruptedException e) {

throw e;

}

});

t2.start();

Thread t3 = new Thread(() -> {

try {

// Simulate some operation taking place

Thread.sleep(1000);

System.out.println("Thread 3: Operation completed");

latch.countDown(); // Decrement the count of the latch by 1

System.out.println("Thread 3: Counted down");

} catch (InterruptedException e) {

throw e;

}

});

t3.start();

// Simulate some operation taking place

Thread.sleep(2000);

System.out.println("Main thread: Operation completed");

latch.countDown(); // Decrement the count of the latch by 1

t1.join();

t2.join();

t3.join();

}

}

In this example, we create a CountDownLatch with a count of 3 and start three threads. Each thread calls await() to wait for the latch to be counted down to 0.

We then simulate some operations taking place in each thread and use countDown() to decrement the count of the latch by 1.

The main thread also simulates an operation taking place and uses countDown() to decrement the count of the latch by 1, causing all threads waiting at the latch to be released.

When you run this program, you'll see that the output depends on the order in which the operations are completed. The first thread will only be released when the count is 0, while the other two threads can be released earlier if their operations complete before the main thread's operation.

This demonstrates how CountDownLatch can help coordinate multiple threads performing independent operations.