CyclicBarrier lets a fixed number of threads wait until all participants reach the same synchronization point.
Problem description:
We need multiple worker threads to finish one phase of work before any of them can safely move to the next phase.
What we are solving actually:
We are solving phased coordination, not mutual exclusion. The goal is to pause progress until all required workers reach the same checkpoint.
What we are doing actually:
- Create a barrier with the exact number of participating workers.
- Let each worker call
await()after finishing the current phase. - Release the whole group only when every worker has arrived.
sequenceDiagram
participant W1 as Worker 1
participant W2 as Worker 2
participant W3 as Worker 3
participant B as Barrier
W1->>B: await()
W2->>B: await()
W3->>B: await()
B-->>W1: release next phase
B-->>W2: release next phase
B-->>W3: release next phase
Real-World Use Cases
- phased simulation systems
- parallel data preparation before a final merge
- batch processing pipelines with step boundaries
How It Works
- create barrier with
Nparties - each worker calls
await() - once all
Narrive, optional barrier action runs - barrier can be reused for next cycle
Java 8 Example
import java.util.concurrent.CyclicBarrier;
public class CyclicBarrierExample {
public static void main(String[] args) {
CyclicBarrier barrier = new CyclicBarrier(3, () ->
System.out.println("All parties arrived. Merge step starts."));
for (int i = 1; i <= 3; i++) {
final int id = i;
new Thread(() -> {
try {
System.out.println("Worker " + id + " preparing data");
Thread.sleep(500L * id);
barrier.await();
System.out.println("Worker " + id + " continues next phase");
} catch (Exception e) {
Thread.currentThread().interrupt();
}
}).start();
}
}
}
Multi-Phase Example Pattern
CyclicBarrier is most useful when the same group repeats phases.
for (int phase = 1; phase <= 3; phase++) {
doPhaseWork(phase);
barrier.await(); // all workers must finish current phase
}
This keeps phase boundaries explicit and deterministic.
Timeout and Broken Barrier Handling
One stuck worker can block everyone. Use timeout overload in real systems:
try {
barrier.await(2, TimeUnit.SECONDS);
} catch (TimeoutException e) {
// one participant was too slow
barrier.reset();
} catch (BrokenBarrierException e) {
// another participant failed or timed out
}
If one thread is interrupted while waiting, the barrier is broken and all waiting parties fail with BrokenBarrierException.
CyclicBarrier vs CountDownLatch vs Phaser
CountDownLatch: one-time wait; not reusable.CyclicBarrier: reusable barrier with fixed participant count.Phaser: dynamic participants and richer phase control.
Choose Phaser when parties can join/leave dynamically.
Operational Pitfalls
- Mismatch between configured parties and actual workers.
- Long-running or blocking barrier actions.
- Ignoring broken-barrier state after failures.
- No timeout policy, causing infinite waits.
Debug steps:
- verify the configured party count matches the real number of workers
- log when each thread reaches
await()and when it resumes - use timeout-based
await()in tests to catch stuck phases quickly - inspect broken-barrier handling after interruption or timeout
JDK 11 and Java 17 Notes
CyclicBarrier remains a stable and relevant choice in JDK 11 and Java 17 for repeated phase synchronization.
Java 21+ Guidance
For request-scoped parallel tasks, prefer StructuredTaskScope style orchestration over manual barriers when possible.
Use CyclicBarrier when you explicitly need reusable phase synchronization.
Java 25 Note
No major usage change expected for CyclicBarrier; API is mature and stable.
Key Takeaways
CyclicBarrieris for reusable phase coordination.- Handle
BrokenBarrierExceptionand interruption correctly. - Use it only when all participants are known upfront.
- Prefer timeout-based
awaitin production workflows.
Comments