Using a phaser rather than 2 count down latches

·

2 min read

Introduction

I came across an excellent article listed in Baeldung's Java weekly.
The article title is How to use the Java CountDownLatch.
I just wanted to build on that article and use a Phaser as an alternative.

Overview

In the last code example, of the above quoted article, 2 count down latches are used to coordinate with threads.
Refer to the article for more details (section 'A real-life example' towards the bottom of the article).

Here, we are going to do something similar.
We have a couple of threads, which start 'doing work' at the same time.
We then wait for all the threads to finish.
Java 17 is used, with simple 'println / printf' statements.

import java.util.concurrent.*;
import java.util.stream.IntStream;

class Coordinator {

    public static void main(String[] args) {
        int numberOfParties = 3;
        usingPhaser(numberOfParties);
    }

    private static void usingPhaser(int numberOfParties) {
        Phaser phaser = new Phaser(numberOfParties + 1);
        IntStream.range(0, numberOfParties)
                .mapToObj(i -> createThread(i, phaser))
                .toList()
                .forEach(Thread::start);

        System.out.println("waiting for all threads to start...");
        phaser.arriveAndAwaitAdvance();
        System.out.println("all threads started");
        System.out.println("waiting for all threads to finish...");
        phaser.arriveAndAwaitAdvance();
        System.out.println("all done!");
    }

    private static Thread createThread(int index, Phaser phaser) {
        Runnable runnable = () -> {
            phaser.arriveAndAwaitAdvance();
            System.out.printf("task %d started%n", index);
            var numberOfSeconds = ThreadLocalRandom.current().nextInt(5);
            try {
                TimeUnit.SECONDS.sleep(numberOfSeconds);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.printf("task %d ended%n", index);
            phaser.arrive();
        };

        return new Thread(runnable);
    }
}

The main threads sets the number of parties that we want to coordinate with (those parties are other threads).
The method usingPhaser creates a Phaser with the total number of stakeholders; we add 1 to the number of parties because the main thread - in addition to the other parties - will also be waiting on the phaser.
The main threads arrives at the phaser and waits; only when all stakeholders arrive, will the next phase begin.
All the other parties also arrive and start 'advancing', to the next phase, at the same time.
The main threads then waits for all the parties to finish their work.

Possible alternative(s)

As always, with concurrency, don't deal with threads directly unless you have to. Use higher level constructs.
Nonetheless, I've tried an alternative using a CyclicBarrier.
I think it was clumsier and less easy to read.

Conclusion

We've built on an article that illustrated how to use the Java CountDownLatch, and we have, for one use case, used a Phaser as an alternative.

Did you find this article valuable?

Support Yet another blog by becoming a sponsor. Any amount is appreciated!