Backend Development 8 min read

Understanding Java CyclicBarrier: Usage, Implementation Details, and Comparison with CountDownLatch

This article explains the concept, practical usage, internal implementation, and key methods of Java's CyclicBarrier, compares it with CountDownLatch, and provides a complete code example demonstrating how multiple threads can repeatedly synchronize at a reusable barrier.

Full-Stack Internet Architecture
Full-Stack Internet Architecture
Full-Stack Internet Architecture
Understanding Java CyclicBarrier: Usage, Implementation Details, and Comparison with CountDownLatch

After introducing CountDownLatch in a previous article, the author points out that CountDownLatch is a one‑time counter and therefore unsuitable for scenarios that require repeated synchronization, such as multiple rounds of a game; the article then introduces CyclicBarrier as a reusable barrier.

CyclicBarrier (literally “cyclic barrier”) provides a reusable synchronization point where a group of threads wait until a predefined number of parties have arrived, after which all waiting threads are released and the barrier can be used again.

The author uses a bus‑loading analogy: a bus departs only when it is full, illustrating how CyclicBarrier fits scenarios where a group must wait until enough participants are present before proceeding.

A side‑by‑side comparison shows that CountDownLatch works like a game loading screen—threads wait for a single event—whereas CyclicBarrier works like a driver waiting for all seats to be filled before the trip starts, emphasizing its repeatable nature.

import java.util.Date; import java.util.Random; import java.util.concurrent.*; public class CyclicBarrierExample { public static void main(String[] args) { final CyclicBarrier cyclicBarrier = new CyclicBarrier(2, new Runnable() { @Override public void run() { System.out.println("People are full, ready to depart: " + new Date()); } }); Runnable runnable = new Runnable() { @Override public void run() { int randomNumber = new Random().nextInt(3) + 1; System.out.println(String.format("I am %s, %d seconds to station, now: %s", Thread.currentThread().getName(), randomNumber, new Date())); try { TimeUnit.SECONDS.sleep(randomNumber); cyclicBarrier.await(); System.out.println(String.format("Thread %s boarded, time: %s", Thread.currentThread().getName(), new Date())); } catch (InterruptedException e) { e.printStackTrace(); } catch (BrokenBarrierException e) { e.printStackTrace(); } } }; ExecutorService threadPool = Executors.newFixedThreadPool(10); threadPool.submit(runnable); threadPool.submit(runnable); threadPool.submit(runnable); threadPool.submit(runnable); threadPool.shutdown(); } }

The execution result demonstrates that when the barrier count is set to 2, the first two threads reach the barrier and trigger the barrier action, then after a short delay the next two threads reach the barrier and trigger the action again, showing the reusable nature of CyclicBarrier.

Internally, CyclicBarrier is built on a ReentrantLock (which itself relies on AQS). It maintains an internal counter that decrements each time a thread calls await() . When the counter reaches zero, all waiting threads are released and the counter is reset to the original parties value for the next round.

Key methods include:

CyclicBarrier(int parties) : creates a barrier for the given number of parties.

CyclicBarrier(int parties, Runnable barrierAction) : also specifies an action to run when the barrier is tripped.

getParties() : returns the number of parties required to trip the barrier.

getNumberWaiting() : returns the number of threads currently waiting.

await() and await(long timeout, TimeUnit unit) : block until the barrier is tripped or an exception occurs (InterruptedException, BrokenBarrierException, TimeoutException).

isBroken() : indicates whether the barrier is in a broken state.

reset() : returns the barrier to its initial state, releasing waiting threads with a BrokenBarrierException and clearing the broken flag.

In summary, CyclicBarrier uses a ReentrantLock to ensure atomic updates of its counter, and its primary advantage over CountDownLatch is the ability to be reused across multiple synchronization cycles, making it a valuable tool for complex multithreaded coordination.

Javabackend developmentconcurrencymultithreadingCountDownLatchCyclicBarrier
Full-Stack Internet Architecture
Written by

Full-Stack Internet Architecture

Introducing full-stack Internet architecture technologies centered on Java

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.