Phasers in Java
There is more to thread synchronization in Java than wait and notify. Java has a very rich set of concurrent utilities that offers much simpler synchronization techniques. But should we care about these techniques? Does the existence of these techniques mean that we should ditch wait and notify, once and for all? Is there life outside planet earth? Let’s come to terms with some of these boiling questions today in the Let’s Talk Java series.
So, let’s start the series, with one of the least known variants of thread synchronization mechanisms — Phasers!
Why should I care about Phasers!
You with your friends Gokul, Jeeva, and Binoy are planning for a weekend get-together. So you plan to meet up at Cafe DeadLock, the most happening place in town. Jeeva and Binoy have plans to do some shopping before the meetup. And you have plans to visit the local pub with Gokul and Binoy, after the meeting. Now try to come up with a solution using notify and wait, to synchronize the actions of 4 of you as in the scenario. Not so easy is it?
The scenario above is an oversimplified use case but should be sufficient to drive home the necessity of alternatives to notify-wait. You may very well be able to come up with a solution using notify-wait and find better waiters than the ones in Cafe DeadLock. What Phasers provide is an easier alternative in doing it.
Okay — Tell me more!
Phasers work well in scenarios where you have multiple phases in your program (Shopping, Cafe, Pub in the scenario above) and you have multiple threads to be coordinated in these phases. What Phaser does is, it acts as a synchronization barrier. So to advance the barrier, all the interested parties should arrive at the barrier.
Wait — so who are these interested parties and what is this barrier? Glad you asked. So for each phase of our weekend adventure, we have different guys interested. For instance, Jeeva and Binoy are down for shopping. So to advance from shopping to the meetup at the cafe, both Jeeva and Binoy should arrive at the barrier (say an exit of the shopping mall). Additionally, there could be new interested parties for the subsequent phase.
The beauty lies in the fact that we can have a different number of parties (threads), advancing to the subsequent phases. Or in other words, you can have new parties interested in the subsequent phases (or existing parties showing disinterest). See, in our example, you and Gokul aren’t interested in the first phase, but are interested from the second phase.
Enough with the Mumbo Jumbo — Let’s see some code!
Take the example above with a pinch of salt, even though it helps forming an idea of the capabilities of Phaser.
Get Bytespub’s stories in your inbox
Join Medium for free to get updates from this writer.
As you might have noticed already, arriveAndAwaitAdvance acts as a barrier and we would need all the interested parties to arrive, for the execution to proceed from that point. The important thing to notice here is that tasks may be registered at any time and the Phaser instance can be reused.
You would have already noticed, that Jeeva de-registered before the final phase, so the final synchronization barrier waits only for 3 arrivals.
Understanding the API
Now that, we have seen some code, let’s take a closer look at some of the APIs we used in the example. Note that, we haven’t made use of every possible method in Phaser, but a few that would help us get started with Phasers. There are also concepts like tiering that would demand a separate post for itself.
int register() As you can see from Line 8 of the Runnable implementation, a party can express its interest by using the register method.
int arriveAndAwaitAdvance()Awaits for all the other interested parties to reach the barrier to resume execution. When all the parties reach the barrier, we move to the next phase of execution. Return the arrival phase number.
int getPhase()Returns the current phase number. The maximum phase number is Integer.MAX_VALUE, after which it restarts at zero. If the Phaser is terminated, returns a negative value.
int arriveAndDeregister()De-registers interest on arrival at the barrier and doesn’t wait for other threads to reach the barrier.
Conclusion
Java has a lot of capabilities in its concurrency department and it’s always preferable to use its synchronizers over notify-wait. Phaser being the most powerful synchronizer of them all is capable of handling complex use cases easily and should be a solid addition to your technical tool-set.
There is more to Phasers than what we have discussed in the article today, but this should serve as a brief introduction to the world of Phasers.
Photo by Clem Onojeghuo on Unsplash





