Phaser works by dividing a task into a series of phases, and each thread has to wait until all threads have reached the current phase before proceeding to the next phase. It is similar to the CyclicBarrier and CountDownLatch classes, but it offers more flexibility and functionality.
What is Phaser in Java?
Yeah, I know It sounds like overhead, but let’s see how it is defined and then we can look at the code.
How is Phaser declared?
Phaser myPhaser = new Phaser();
There are multiple constructors for phasers that accept different values like below:
-
Phaser myPhaser = new Phaser() - This builds a phaser with no
registered parties at first. Only after registering for this phaser may a
thread use it.
-
Phaser myPhaser = new Phaser(int parties) - This establishes
a phaser in which each party must have a certain number of threads to
progress to the next phase.
-
Phaser myPhaser = new Phaser(Phaser parent) - For the new
object, this defines a parent phaser. The number of parties registered is
set to zero.
- Phaser myPhaser = new Phaser(Phaser parent, int parties) - This defines a parent phaser for the newly created object as well as the number of parties required to progress to the next phase.
Now, we know that phaser is used for thread synchronization. But, it is not just that. We can also monitor it. While synchronization techniques can only be used by registered parties, any caller can observe the present state of a phaser. There are a total of getRegisteredParties() parties at any given time, with getArrivedParties() arriving at the current phase (getPhase()).
Also, Phasers support tiering of phases. To decrease conflict, phasers can be tiered (i.e. built-in tree structures). Phasers with a large number of parties that would normally have high synchronization contention costs might be configured so that groups of sub-phasers share a common parent. Even though it has a higher per-operation overhead, this might substantially boost throughput.
Registration and deregistration of kid phasers with their parents are maintained automatically in a tree of tiered phasers. The child phaser gets registered with its parent if the number of registered parties of a child phaser becomes non-zero (as determined by the Phaser(Phaser,int) function Object() { [native code] }, register(), or bulkRegister(int)).
Now you all must be thinking we know the constructors and what Phaser is, but how are they used? Well no worries, let’s see the code and then understand it!
2. Phaser working code Example
import java.util.concurrent.Phaser;
class MyThread implements Runnable{
Phaser myPhaser;
String threadName;
MyThread(Phaser myPhaser, String threadName) {
this.myPhaser = myPhaser;
this.threadName = threadName;
myPhaser.register();
new Thread(this).start();
}
@Override
public void run() {
// phase 1 of our code.
System.out.println("This is Phase one for : "+this.threadName);
// creating a phaser barrier for all threads to sync
myPhaser.arriveAndAwaitAdvance();
try {
Thread.sleep(99);
} catch (InterruptedException e) {
e.printStackTrace();
}
// start new phase of execution, phase 2 of code
System.out.println("This is Phase two for : "+this.threadName);
// creating a barrier for all threads to sync
myPhaser.arriveAndAwaitAdvance();
try {
Thread.sleep(99);
} catch (InterruptedException e) {
e.printStackTrace();
}
// start new phase of execution, phase 3 of code
System.out.println("This is Phase three for : "+this.threadName);
myPhaser.arriveAndDeregister();
}
}
public class MyPhaser {
public static void main(String[] args) {
Phaser myPhaser = new Phaser();
myPhaser.register();
System.out.println("let's start phaser example");
int phase=0;
MyThread cat = new MyThread(myPhaser, "cat");
MyThread dog = new MyThread(myPhaser, "dog");
MyThread elephant = new MyThread(myPhaser, "elephant");
myPhaser.arriveAndAwaitAdvance();
System.out.println("Ending phase one");
myPhaser.arriveAndAwaitAdvance();
System.out.println("Ending phase two");
myPhaser.arriveAndAwaitAdvance();
System.out.println("Ending phase three");
}
}
Explanation of Code
Now, let’s understand what we did. First of all, there are 4 threads in the system, not 3!You heard right! 3 threads and 1 main thread. All these threads are associated with a phaser. For associating a thread to a phaser, we use the method “register” of a phaser. This registers the current thread with a current phaser. Now when the execution of all the threads starts, the run method will start for all of them.
Now, the interesting fact is the method “arriveAndAwaitAdvance”. This method waits for other threads by suspending the thread's execution at a phase. The current phase number is returned, or a negative value if the phaser has been terminated.
These methods are synchronized and they know that all four threads are now waiting on this method, and so, the execution of the program starts further. You can see in the output how the code proceeds. Feel free to try and test different combinations and see the output! Also, note that output may slightly vary depending upon the system and its performance.
Important Points about Phaser in Java
- Phaser was introduced in java 7 and is a part of the java.util.concurrent library.
- Like a CyclicBarrier, a Phaser can be awaited repeatedly in java.
- The maximum number of parties that could be registered with a phaser at a time is 65535, if we try to register more parties IllegalStateException will be thrown in java.
- Phasers may be constructed in tree structures to reduce contention in java.
- Phaser is used for easy synchronization between threads and create a barrier before the execution of phases in any code.
When to use Phaser in Java? Use Cases
You can use Phaser when the management of software processes is done in stages. For example, the first process might be gathering requirements, followed by software development, and finally testing.The second phase will not begin until the first phase has been finished, and the third phase will not begin until the second phase has been completed.
That's all about Phaser in Java. It's one of the important concurrency utils for Java developers and every Java programmer should learn it along with CyclicBarrier, CounntDowLatch, and CompletableFurure as you can use Phaser to build logic in which threads need to wait on the barrier before going to the next step of execution.
You can also create and coordinate multiple phases of execution, reusing a Phaser instance for each program phase and each phase can also have a different number of threads waiting for advancing to another phase.
Other Java Concurrency Articles you may like
- 10 Java Multithreading and Concurrency Best Practices (article)
- Difference between atomic, volatile, and synchronized (answer)
- Difference between CyclicBarrier and CountDownLatch in Java? (answer)
- How to avoid deadlock in Java? (answer)
- Top 50 Multithreading and Concurrency Questions in Java (questions)
- Top 5 Books to Master Concurrency in Java (books)
- What is happens-before in Java concurrency? (answer)
- Understanding the flow of data and code in Java program (answer)
- Is Java Concurrency in Practice still valid (answer)
- How to do inter-thread communication in Java using wait-notify? (answer)
- 5 Courses to Learn Java Multithreading in-depth (courses)
- 10 Advanced books for Experienced Programmers (books)
- 50+ Thread Interview Questions for Beginners (questions)
- The Java Developer RoadMap (roadmap)
- Top 5 skills to Crack Coding interviews (article)
- 10 Advanced Core Java Courses for Experienced Programmers (courses)
Hope you guys enjoyed the article and learned something new about java. Do try hands-on for Phaser and make sure you understand the behavior and output to further solidify your knowledge about Phaser.
P. S. - If you are new to Java Concurrency and Multithreading and looking for a free online training course to learn Multithreading and Concurrency basics then I also suggest you check out this free Java Multithreading course on Udemy. It's completely free and all you need is a free Udemy account to join this course.
1 comment :
What is difference between Phaser and CompletableFuture in Java?
Post a Comment