1. What Is a CyclicBarrier?
A CyclicBarrier is a synchronization aid that allows a set of threads to all wait for each other to reach a common barrier point. Once all threads reach the barrier, they are released to continue their work. The barrier is called "cyclic" because it can be reused after the waiting threads are released.
1.1 Key Features of CyclicBarrier
- Reusability: Unlike other synchronization aids like CountDownLatch, a CyclicBarrier can be reset and used again after all threads have been released.
- Barrier Action: Optionally, you can specify a barrier action that is executed once all threads reach the barrier.
- Flexibility: It is useful in scenarios where multiple threads need to wait for each other to complete a phase before proceeding to the next.
1.2 How CyclicBarrier Works
- Initialization: A CyclicBarrier is initialized with a number of parties (threads) that need to wait at the barrier.
- Waiting: Each thread calls the await() method on the barrier.
- Release: When the last thread reaches the barrier, all waiting threads are released, and the optional barrier action (if provided) is executed.
- Reuse: The barrier is reset and can be used again for another cycle of waiting.
- Batch Processing: When processing data in batches, threads can use a CyclicBarrier to synchronize at the end of each batch.
- Parallel Algorithms: In parallel algorithms, threads often need to synchronize after completing certain phases of computation.
2. Practical Examples and Demos
To better understand how a CyclicBarrier works, let's look at a practical example and demo.
Here's a simple example demonstrating the use of CyclicBarrier:
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
public class CyclicBarrierDemo {
public static void main(String[] args) {
final int numberOfThreads = 3;
CyclicBarrier barrier = new CyclicBarrier(numberOfThreads, new BarrierAction());
for (int i = 0; i < numberOfThreads; i++) {
new Thread(new Task(barrier)).start();
}
}
}
class Task implements Runnable {
private final CyclicBarrier barrier;
Task(CyclicBarrier barrier) {
this.barrier = barrier;
}
@Override
public void run() {
try {
System.out.println(Thread.currentThread().getName() + " is waiting at the barrier.");
barrier.await();
System.out.println(Thread.currentThread().getName() + " has passed the barrier.");
} catch (InterruptedException | BrokenBarrierException e) {
e.printStackTrace();
}
}
}
class BarrierAction implements Runnable {
@Override
public void run() {
System.out.println("Barrier Action executed. All threads are released.");
}
}
When you run the above code, you will observe the following sequence:
- Each thread prints a message indicating that it is waiting at the barrier.
- Once all threads reach the barrier, the BarrierAction is executed, printing "Barrier Action executed. All threads are released."
- Each thread then prints a message indicating that it has passed the barrier.
Here's an example output:
Thread-0 is waiting at the barrier.
Thread-1 is waiting at the barrier.
Thread-2 is waiting at the barrier.
Barrier Action executed. All threads are released.
Thread-0 has passed the barrier.
Thread-1 has passed the barrier.
Thread-2 has passed the barrier.
A CyclicBarrier is an invaluable tool for coordinating multiple threads in Java. It allows threads to wait for each other and can be reused across multiple cycles, making it ideal for many synchronization scenarios. Whether you're processing data in batches or implementing parallel algorithms, understanding how to use CyclicBarrier effectively will enhance your multi-threaded programming skills.
Feel free to comment below if you have any questions or need further clarification on using CyclicBarrier in your projects!
Read posts more at : What Is CyclicBarrier? Key Facts and Examples Explained