Skip to main content
  1. Java Concurrency (java.util.concurrent)/

Phaser

2 mins

Phaser is a more sophisticated and flexible alternative to both CountDownLatch and CyclicBarrier. It is designed for coordinating any number of threads that may change over time.

Source Code #

View Source on GitHub

Mechanism: The “Tiered Barrier” #

Internally, Phaser uses a complex state-management approach. It allows threads to register and deregister dynamically. When many threads are involved, Phaser can be structured into tiers to reduce contention on its internal state. This makes it more scalable than CyclicBarrier for high thread counts.

public int register();
public int arrive();
public int arriveAndAwaitAdvance();
public int arriveAndDeregister();

A Phaser maintains a “phase number” that increments each time the barrier is tripped. Threads can wait for a specific phase number or just the next one.

Canonical Usage #

When to use: Use Phaser when the number of threads is unknown at compile time or can change dynamically during execution. It is also ideal for variable-length phases where some threads may drop out after a certain phase.

Common Patterns:

  • Dynamic Task Graph: A main task starts multiple sub-tasks, which may in turn spawn more tasks. Each task registers with the same Phaser and arrives when done.
  • Tiered Multi-phase Processing: Using multiple phasers organized into a tree to coordinate thousands of worker threads efficiently.
  • Replacement for CountDownLatch: A Phaser can act like a one-time latch by registering one party and never deregistering it until a specific event happens.
// Phaser with dynamic registration
Phaser phaser = new Phaser(1); // Register the main thread

// Start multiple tasks dynamically
for (Task task : tasks) {
    phaser.register(); // Dynamically register a new task
    executor.execute(() -> {
        try {
            doWork();
        } finally {
            phaser.arriveAndDeregister(); // Deregister when task is finished
        }
    });
}

// Main thread waits until all registered tasks have arrived and deregistered
phaser.arriveAndAwaitAdvance();
System.out.println("All dynamic tasks completed.");

Advantages Over CyclicBarrier #

  • Dynamism: You don’t need to know the number of parties upfront.
  • Deregistration: Threads can stop participating in the barrier without breaking it.
  • Scalability: Tiering reduces lock contention.