Phaser solves the problem that both CountDownLatch and CyclicBarrier have a fixed number of parties decided at construction. A Phaser lets threads register and deregister dynamically across phases, so it fits computations where the number of participants changes between rounds — and it is reusable across an arbitrary number of phases without throwing it away like a latch.
The two gaps it fills
- CountDownLatch is one-shot with a fixed count — no reuse, no changing the count.
- CyclicBarrier is reusable but the number of parties is locked at construction — you cannot add or remove participants mid-run, and threads can't drop out cleanly.
A Phaser does both: dynamic membership and multiple phases.
How it works
A phaser tracks parties (registered participants) and a monotonically increasing phase number. Each party calls arriveAndAwaitAdvance() to signal arrival and block until all registered parties arrive; when the last one does, the phaser advances to the next phase and releases everyone.
register()/bulkRegister(n)— add parties, even mid-flight.arrive()— signal arrival without blocking.arriveAndAwaitAdvance()— arrive and wait for phase advance (the barrier behavior).arriveAndDeregister()— arrive and permanently drop out, shrinking the party count.- Override
onAdvance(phase, parties)to run a per-phase action and to returntruewhen the phaser should terminate.
Phaser phaser = new Phaser(1); // register self as controller
for (Task t : tasks) {
phaser.register(); // add a party dynamically
new Thread(() -> {
for (int p = 0; p < t.rounds(); p++) {
t.runPhase(p);
phaser.arriveAndAwaitAdvance(); // sync at each phase
}
phaser.arriveAndDeregister(); // leave when done
}).start();
}
phaser.arriveAndDeregister(); // controller drops out -> may terminate
phase 0: P1 P2 P3 -> all arrive -> advance phase 1: P1 P2 P3 P4 <- P4 registered phase 2: P1 P3 P4 <- P2 deregistered (arriveAndDeregister) ... terminates when parties drop to 0 or onAdvance returns true
Extra reach
Phasers also tier: a parent phaser with child phasers reduces contention for large party counts. And onAdvance returning true (or party count hitting zero) cleanly terminates the phaser, which a barrier has no equivalent for.