TL;DR: In this context use Phaser.arriveAndDeregister() for a non-blocking signal to the waiters of the phaser, which corresponds to operation CountDownLatch.countDown().
Phaser and CountDownLatch. The first thing to clarify is that a Phaser cannot generally encode a CountDownLatch. The tasks synchronizing with a Phaser must all wait for each other (all-to-all synchronization). In a CountDownLatch, there is a group of tasks that awaits some other task to open the latch.
Phaser and CyclicBarrier. Both of these mechanisms are used for all-to-all synchronization. The two differences between them are: 1) a Phaser the set of tasks using the phaser may grow during the life cycle of the phaser, whereas in a CyclicBarrier the number of participants is fixed; 2) with Phasers, a task may notify other members (participants) and not wait as long as it deregisters from that phaser, whereas all tasks using the cyclic barrier can only wait-and-notify.
Encoding a CountDownLatch with a Phaser. To encode a CountDownLatch(1) with a phaser you need to keep in mind the following:
- Number of parties = number of waiters + 1: The number of registered parties, either via
new Phaser(PARTIES_COUNT) or via Phaser.register.
CountDown.await() = Phaser.arriveAndAwaitAdvance()
CountDown.countDown() = Phaser.arriveAndDeregister()
Example. Suppose you want the child task to wait for the parent's task signal. Using CountDownLatch you would write:
import java.util.concurrent.*;
class CountDownExample {
public static void main(String[] args) throws Exception {
CountDownLatch l = new CountDownLatch(1);
new Thread(() -> {
try {
l.await();
System.out.println("Child: running");
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}).start();
System.out.println("Parent: waiting a bit.");
Thread.sleep(100);
l.countDown();
}
}
Using a Phaser you would write:
import java.util.concurrent.*;
class PhaserExample {
public static void main(String[] args) throws Exception {
Phaser ph = new Phaser(2); // 2 parties = 1 signaler and 1 waiter
new Thread(() -> {
ph.arriveAndAwaitAdvance();
System.out.println("Child: running");
}).start();
System.out.println("Parent: waiting a bit.");
Thread.sleep(100);
ph.arriveAndDeregister();
}
}
You might want to look at this post for another example.