Concurrency in Java can be tricky, but Javaβs java.util.concurrent package provides powerful utilities to handle multithreading gracefully. One such utility is the CyclicBarrier β a synchronization aid that allows a set of threads to all wait for each other to reach a common barrier point.
π What is CyclicBarrier?
CyclicBarrier is used to make threads wait at a common barrier point. Once all threads have reached the barrier, they are released to continue execution. It's called cyclic because it can be reused after the waiting threads are released β unlike CountDownLatch which cannot be reset.
π§ When to Use CyclicBarrier?
Use CyclicBarrier when:
- You want multiple threads to perform independent tasks and wait for others before continuing.
- You have a multi-phase task, where threads need to synchronize after each phase.
- You are simulating a game round, parallel data processing, or distributed computation steps.
β Real-World Example: Worker Threads Synchronizing Before Task Execution
Letβs imagine you have 3 worker threads that perform some setup, then must all wait until everyone is ready before starting the main task.
π‘ Step-by-step Breakdown:
- Create a
CyclicBarrierwith a count of 3. - Each thread does its preparation work.
- Each thread then calls
await()to wait for others. - When all threads reach the barrier, a barrier action runs (optional).
- All threads proceed with the main task.
π§ͺ Code Snippet
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
public class CyclicBarrierExample {
// Barrier for 3 threads with a barrier action
private static final CyclicBarrier barrier = new CyclicBarrier(3, () -> {
System.out.println("\nβ
All workers reached the barrier. Let's start the main task!\n");
});
static class Worker implements Runnable {
private final String name;
Worker(String name) {
this.name = name;
}
@Override
public void run() {
try {
System.out.println(name + " π οΈ is doing preparation...");
Thread.sleep((long) (Math.random() * 3000));
System.out.println(name + " βΈοΈ waiting at the barrier...");
barrier.await(); // Wait for others
System.out.println(name + " π starting the main task.");
} catch (InterruptedException | BrokenBarrierException e) {
System.err.println(name + " β error: " + e.getMessage());
}
}
}
public static void main(String[] args) {
// Launch 3 worker threads
new Thread(new Worker("Worker-1")).start();
new Thread(new Worker("Worker-2")).start();
new Thread(new Worker("Worker-3")).start();
}
}
π₯οΈ Sample Output
Worker-2 π οΈ is doing preparation...
Worker-3 π οΈ is doing preparation...
Worker-1 π οΈ is doing preparation...
Worker-1 βΈοΈ waiting at the barrier...
Worker-2 βΈοΈ waiting at the barrier...
Worker-3 βΈοΈ waiting at the barrier...
β
All workers reached the barrier. Let's start the main task!
Worker-2 π starting the main task.
Worker-1 π starting the main task.
Worker-3 π starting the main task.
π Reusability of CyclicBarrier
The same barrier can be reused by calling await() again. If your task has multiple stages (e.g., MapReduce phases), this becomes incredibly powerful.
β οΈ Exception Handling Tips
-
BrokenBarrierException: Thrown if a thread is interrupted while waiting or if another thread leaves the barrier prematurely. - Always wrap
await()in atry-catchblock.
π§ Comparison with CountDownLatch
| Feature | CyclicBarrier |
CountDownLatch |
|---|---|---|
| Reusable? | β Yes | β No |
| Barrier Action? | β Yes (optional Runnable) | β No |
| Usage Style | All threads wait | One or more threads wait for others to finish |
π Real Use Cases
- Game engines: Wait for all players to be ready before starting a round.
- Simulations: Synchronize steps in time-stepped simulations.
- Parallel computing: Wait for all worker threads to complete a phase before starting the next.
π§΅ Pro Tip
If you have a dynamic number of threads, CyclicBarrier might not be ideal. In such cases, consider alternatives like Phaser.
π Conclusion
CyclicBarrier is an elegant solution for coordinating multiple threads that must wait for each other before proceeding. It's easy to implement and highly useful in collaborative parallel processing tasks.
π What's Next?
- π Try using
CyclicBarrierfor multiple phases - π Combine with
ExecutorServicefor cleaner thread management - βοΈ Explore
Phaserfor more dynamic thread coordination
Top comments (0)