Mastering Java’s Phaser: A Flexible Alternative to CountDownLatch and CyclicBarrier

This article explains how Java’s Phaser class extends the capabilities of CountDownLatch and CyclicBarrier, offering dynamic phase management for multistage tasks, details its constructors and key methods, compares usage scenarios, and provides a complete code demo illustrating practical implementation.

FunTester
FunTester
FunTester
Mastering Java’s Phaser: A Flexible Alternative to CountDownLatch and CyclicBarrier

Overview

The Phaser class in Java’s java.util.concurrent package provides functionality that overlaps with CountDownLatch and CyclicBarrier but adds richer semantics and more flexible usage. It is especially suitable for scenarios where a task is divided into multiple phases and a group of threads must synchronize at each phase, while allowing the number of parties to be changed dynamically during execution.

Basic Introduction

The most common constructor of Phaser takes a single int argument representing the initial number of registered parties, similar to CountDownLatch. More complex constructors involving a parent Phaser exist but are rarely needed for typical testing.

/**
 * Creates a new phaser with the given number of registered
 * unarrived parties, no parent, and initial phase number 0.
 *
 * @param parties the number of parties required to advance to the
 * next phase
 * @throws IllegalArgumentException if parties less than zero
 * or greater than the maximum number of parties supported
 */
public Phaser(int parties) {
    this(null, parties);
}

Key Methods

After constructing a Phaser, the primary synchronization method is await(), which blocks the calling thread until all registered parties arrive. An overloaded version accepts a timeout and a TimeUnit. If a timeout occurs, a BrokenBarrierException is thrown, mirroring the behavior of CyclicBarrier. Other important methods include: arriveAndAwaitAdvance(): Signals that the current thread has finished the current phase and waits for others; if it is the last arriving thread, it returns the next phase number. arrive(): Signals arrival without waiting, returning the next phase number. awaitAdvance(int phase): Waits until the specified phase completes, returning immediately if the phaser is terminated or the phase has already advanced.

Additional Timeout‑Enabled Methods

awaitAdvanceInterruptibly(int phase)

: Same as awaitAdvance but throws InterruptedException if the waiting thread is interrupted.

awaitAdvanceInterruptibly(int phase, long timeout, TimeUnit unit)

: Same as the previous method but throws TimeoutException on timeout.

Practical Demo

The following example demonstrates a race‑style test where three player threads synchronize across multiple phases using a custom Phaser that overrides onAdvance to log phase transitions. The demo shows registration, phase advancement, deregistration, and termination handling.

public class AR extends FanLibrary {
    public static void main(String[] args) throws InterruptedException {
        final Phaser phaser = new Phaser(3) {
            @Override
            protected boolean onAdvance(int phase, int registeredParties) {
                System.out.println("====== " + phase + " ======");
                return registeredParties == 0;
            }
        };
        for (int i = 0; i < 3; i++) {
            new Thread(new Player(phaser), "player" + i).start();
        }
        phaser.register();
        System.out.println("Game Start");
        sleep(2);
        phaser.arriveAndDeregister();
        int i = phaser.awaitAdvance(2);
        output(i);
        while (!phaser.isTerminated()) {
            sleep(1000);
            output(111111111111L);
        }
        System.out.println("Game Over");
    }

    static class Player implements Runnable {
        private final Phaser phaser;
        Player(Phaser phaser) { this.phaser = phaser; }
        @Override
        public void run() {
            phaser.arriveAndAwaitAdvance(); // phase 0
            sleep(1000);
            System.out.println(Thread.currentThread().getName() + " ready");
            phaser.arriveAndAwaitAdvance(); // phase 1
            phaser.arriveAndAwaitAdvance(); // phase 2
            sleep(1000);
            phaser.arriveAndAwaitAdvance(); // phase 3
            sleep(1000);
            phaser.arriveAndAwaitAdvance(); // phase 4
            System.out.println(Thread.currentThread().getName() + " arrived");
            phaser.arriveAndDeregister();
        }
    }
}
Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaconcurrencySynchronizationmultithreadingPhaser
FunTester
Written by

FunTester

10k followers, 1k articles | completely useless

0 followers
Reader feedback

How this landed with the community

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.