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.