CountDownLatch and CyclicBarrier in Java
Introduction
In concurrent programming, synchronization is crucial to ensure proper coordination between multiple threads. Java provides powerful utilities in the java.util.concurrent
package to handle such synchronization. Two commonly used concurrency utilities are CountDownLatch and CyclicBarrier.
Both serve different purposes but are often confused due to their similarities. In this article, we will explore CountDownLatch and CyclicBarrier, their differences, and when to use them.
1. CountDownLatch
What is CountDownLatch?
CountDownLatch
is a synchronization aid that allows one or more threads to wait until a set of operations being performed by other threads complete. It is often used to ensure that a particular task does not proceed until a given number of prerequisites have been completed.
How CountDownLatch Works
-
It is initialized with a count.
-
Threads call
countDown()
to decrement the count. -
Threads waiting on
await()
will be blocked until the count reaches zero. -
Once the count reaches zero, all waiting threads are released.
-
The count cannot be reset after reaching zero.
Example of CountDownLatch
Scenario: Waiting for Multiple Threads to Complete
import java.util.concurrent.CountDownLatch;
class Worker extends Thread {
private CountDownLatch latch;
public Worker(CountDownLatch latch, String name) {
super(name);
this.latch = latch;
}
@Override
public void run() {
try {
System.out.println(getName() + " is performing a task.");
Thread.sleep(2000); // Simulating work
System.out.println(getName() + " has finished.");
latch.countDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class CountDownLatchExample {
public static void main(String[] args) throws InterruptedException {
CountDownLatch latch = new CountDownLatch(3);
new Worker(latch, "Worker-1").start();
new Worker(latch, "Worker-2").start();
new Worker(latch, "Worker-3").start();
latch.await(); // Main thread waits until all workers finish
System.out.println("All workers have finished. Main thread resumes.");
}
}
Output:
Worker-1 is performing a task.
Worker-2 is performing a task.
Worker-3 is performing a task.
Worker-1 has finished.
Worker-2 has finished.
Worker-3 has finished.
All workers have finished. Main thread resumes.
Use Cases of CountDownLatch
-
Ensuring a service starts only after all dependencies have initialized.
-
Waiting for multiple threads to complete before proceeding.
-
Simulating multiple users performing an operation concurrently (e.g., in load testing).
2. CyclicBarrier
What is CyclicBarrier?
CyclicBarrier
is another synchronization aid that allows a group of threads to wait for each other at a common barrier before proceeding further. Unlike CountDownLatch
, it can be reused after the barrier is released.
How CyclicBarrier Works
-
It is initialized with a count (the number of threads required to reach the barrier).
-
Each thread calls
await()
to indicate it has reached the barrier. -
Once the required number of threads has called
await()
, all threads are released. -
The barrier can be reset and used again.
Example of CyclicBarrier
Scenario: Simulating a Race
import java.util.concurrent.CyclicBarrier;
class Racer extends Thread {
private CyclicBarrier barrier;
public Racer(CyclicBarrier barrier, String name) {
super(name);
this.barrier = barrier;
}
@Override
public void run() {
try {
System.out.println(getName() + " is ready.");
barrier.await(); // Waiting for all racers
System.out.println(getName() + " starts racing!");
} catch (Exception e) {
e.printStackTrace();
}
}
}
public class CyclicBarrierExample {
public static void main(String[] args) {
int numRacers = 3;
CyclicBarrier barrier = new CyclicBarrier(numRacers, () ->
System.out.println("All racers are ready. Start the race!")
);
new Racer(barrier, "Racer-1").start();
new Racer(barrier, "Racer-2").start();
new Racer(barrier, "Racer-3").start();
}
}
Output:
Racer-1 is ready.
Racer-2 is ready.
Racer-3 is ready.
All racers are ready. Start the race!
Racer-1 starts racing!
Racer-2 starts racing!
Racer-3 starts racing!
Use Cases of CyclicBarrier
-
Simulating multi-threaded tasks that need to start together.
-
Dividing a task into subtasks that need to synchronize at certain points.
-
Multiplayer gaming where players must wait until everyone is ready.
3. Differences Between CountDownLatch and CyclicBarrier
Feature | CountDownLatch | CyclicBarrier |
---|---|---|
Reset Capability | Cannot be reset | Can be reset and reused |
Usage | One-time use | Can be used multiple times |
Number of Threads | Can be different each time | Fixed number of threads required |
When Threads Proceed | When count reaches zero | When all threads reach the barrier |
Example Use Case | Waiting for workers to complete | Synchronizing multiple threads |
Conclusion
Both CountDownLatch and CyclicBarrier provide powerful synchronization mechanisms for multi-threaded applications.
-
Use
CountDownLatch
when you need a one-time event synchronization where a thread waits for others to complete. -
Use
CyclicBarrier
when you need threads to synchronize repeatedly at certain points in execution.
Understanding these utilities will help you write efficient and synchronized multi-threaded Java applications.
Sign up here with your email
ConversionConversion EmoticonEmoticon