CyclicBarrier, Phaser and Exchanger
Synchronizers that reset: hold every worker at the end of a round, then release them together.
Open this lesson in the learning hubKey points
CountDownLatchcounts down once and is done.CyclicBarrierresets itself, so it works round after round.await()blocks until all parties arrive. The last arrival runs the optional barrier action, then everyone continues.- If a party dies the barrier breaks: every other waiter gets a
BrokenBarrierExceptioninstead of hanging forever. Phaseris a barrier whose party count can change:register()andarriveAndDeregister()at any phase.Exchangerpairs two threads and swaps a value between them, which suits fill-one-buffer-drain-the-other loops.
Example
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Phaser;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
public class Main {
public static void main(String[] args) throws InterruptedException {
int workers = 3, rounds = 3;
AtomicInteger merges = new AtomicInteger();
// The barrier action runs once per round, on the last thread to arrive.
CyclicBarrier barrier = new CyclicBarrier(workers,
() -> System.out.println("round " + merges.incrementAndGet() + " merged, all 3 released"));
ExecutorService pool = Executors.newFixedThreadPool(workers);
for (int w = 1; w <= workers; w++) {
int id = w;
pool.execute(() -> {
try {
for (int r = 1; r <= rounds; r++) {
Thread.sleep(10L * id); // deliberately uneven work
barrier.await(); // nobody starts the next round early
}
} catch (InterruptedException e) { Thread.currentThread().interrupt(); }
catch (BrokenBarrierException e) { System.out.println("barrier broke"); }
});
}
pool.shutdown();
pool.awaitTermination(5, TimeUnit.SECONDS);
System.out.println("barrier reused : " + merges.get() + " times (a latch fires only once)");
Phaser phaser = new Phaser(1); // main registers itself
for (int w = 1; w <= 2; w++) {
phaser.register(); // parties can join at any phase
int id = w;
new Thread(() -> {
System.out.println("phaser worker " + id + " arrived in phase " + phaser.getPhase());
phaser.arriveAndDeregister(); // and leave again, unlike a barrier
}).start();
}
phaser.arriveAndAwaitAdvance();
System.out.println("phase now : " + phaser.getPhase() + ", parties left " + phaser.getRegisteredParties());
}
}
Latch for one gate, barrier for repeated rounds, phaser when the crowd changes size.
This is a reading copy. The full lesson — with the visual explainer, the interactive lab and a Run button for the code — lives in the Multithreading course, and every lesson in it is listed on the Multithreading contents page.