original link
OverviewPhaser is introduced in the Java 7 concurrency package, and its functionality overlaps with cyclicbarrier and Countdownlatch, but provides more flexible usage, such as support for dynamically adjusting the number of registration tasks. This paper makes a simple analysis on the basis of the sample code with phaser.
Glossary
RegistrationPhaser supports dynamically adjusting the number of registration tasks through the Register () and bulkregister (int parties) methods, and also supports specifying the initial number through its constructors. At the right time, phaser supports reducing the number of registration tasks, such as Arriveandderegister (). The maximum number of registered tasks allowed for a single phaser instance is 65535.
ArrivalAs the name of the Phaser class implies, each phaser instance maintains a phase number with an initial value of 0. Whenever all registered tasks arrive at Phaser, phase number is incremented and zeros are cleared after the integer.max_value is exceeded. The arrive () and Arriveandderegister () methods are used to record arrival, and the Arriveandawaitadvance () method is used to record arrivals and wait for other unreachable tasks.
terminationPhaser support terminated. After the phaser terminates, the calling register () and bulkregister (int parties) methods have no effect, and the Arriveandawaitadvance () method returns immediately. The timing of the trigger termination is when the protected boolean onadvance (int phase, int registeredparties) method returns, and if the method returns True, then Phaser is terminated. The default implementation is to return true when the number of registered tasks is 0 o'clock (that is, returns registeredparties = 0;). In addition, the Forcetermination () method is used to force termination, and the isterminated () method is used to determine whether it has terminated.
tieringPhaser supports hierarchies that construct a tree structure through constructors Phaser (phaser parent) and Phaser (phaser parent, int parties). This helps to mitigate the competition caused by registering too many tasks on a single phaser, thereby enhancing throughput, at the cost of increasing the cost of a single operation.
Sample Usage
Sample 1In some scenarios, we want to control the startup time of multiple threads: for example, in a concurrency-related unit test, you sometimes need to control the thread's startup time for maximum concurrency, usually using Countdownlatch, and here's the Phaser version.
Import Java.util.concurrent.Phaser;
public class PhaserTest1 {public
static void Main (String args[]) {
//
Final int count = 5;
Final Phaser Phaser = new Phaser (count);
for (int i = 0; i < count; i++) {
System.out.println ("Starting Thread, ID:" + i);
Final thread thread = new Thread (new Task (I, Phaser));
Thread.Start ();
}
public static class Task implements Runnable {
//
private final int id;
Private final Phaser Phaser;
public Task (int ID, Phaser phaser) {
this.id = ID;
This.phaser = Phaser;
}
@Override public
Void Run () {
phaser.arriveandawaitadvance ();
System.out.println ("in Task.run (), Phase:" + phaser.getphase () + ", ID:" + this.id);
}}}
In the example above, since the thread is start in a loop, the timing of the start is at a certain interval. In this case, the time when these threads actually start working is after all the threads have called phaser.arriveandawaitadvance ().
Also, if you pay attention to the signature of the Arriveandawaitadvance () method, you will find that it does not throw interruptedexception, in fact, the Arriveandawaitadvance () method does not return even if the current thread is interrupted , but continue to wait. If you want to be interrupted while waiting, or you can time out, you need to use the following methods:
Awaitadvance (Arrive ()) //equivalent to Arriveandawaitadvance ()
awaitadvanceinterruptibly (int phase)
awaitadvanceinterruptibly (int phase, long timeout, timeunit unit)
Sample 2Sometimes we want to really start the execution of a task only when some external conditions are met, for example:
Import Java.io.BufferedReader;
Import Java.io.InputStreamReader;
Import Java.util.concurrent.Phaser; public class PhaserTest2 {public static void main (String args[]) throws Exception {//FINAL
Phaser Phaser = new Phaser (1);
for (int i = 0; i < 5; i++) {phaser.register ();
SYSTEM.OUT.PRINTLN ("Starting Thread, ID:" + i);
Final thread thread = new Thread (new Task (I, Phaser));
Thread.Start ();
}//System.out.println ("Press ENTER to continue");
BufferedReader reader = new BufferedReader (new InputStreamReader (system.in));
Reader.readline ();
Phaser.arriveandderegister ();
The public static class Task implements Runnable {//private final int id;
Private final Phaser Phaser;
public Task (int ID, Phaser phaser) {this.id = ID; This.Phaser = Phaser;
@Override public void Run () {phaser.arriveandawaitadvance ();
System.out.println ("in Task.run (), Phase:" + phaser.getphase () + ", ID:" + this.id); }
}
}
In the example above, the task does not really start until the user presses the carriage return. It should be noted that the Arriveandderegister () method is not blocked and returns the phase number (arrive method) at the time of arrival.
Sample 3
Import Java.util.concurrent.Phaser; public class PhaserTest3 {public static void main (String args[]) throws Exception {//FINAL
int count = 5;
Final int phasetoterminate = 3; Final Phaser Phaser = new Phaser (count) {@Override protected boolean onadvance (int phase, int
registeredparties) {System.out.println ("= = =" + phase + "= ="); return phase >= Phasetoterminate | |
registeredparties = 0;
}
};
for (int i = 0; i < count; i++) {System.out.println ("Starting Thread, ID:" + i);
Final thread thread = new Thread (new Task (I, Phaser));
Thread.Start ();
} public static class Task implements Runnable {//private final int id;
Private final Phaser Phaser; public Task (int ID, Phaser phaser) {
This.id = ID;
This.phaser = Phaser;
@Override public void Run () {do {try {
Thread.Sleep (500); The catch (Interruptedexception e) {//NOP} System.out.println ("I
n Task.run (), Phase: "+ phaser.getphase () +", ID: "+ this.id);
Phaser.arriveandawaitadvance ();
while (!phaser.isterminated ()); }
}
}
The barrier action in this example simply prints a piece of information and terminates phaser after a specified number of iterations.
Sample 4In the case of Smaple 3, the main thread terminated before the end of the other worker threads. If you want the main thread to wait for these worker threads to end, in addition to using Thread.Join (), you can try the following ways:
Import Java.util.concurrent.Phaser; public class PhaserTest4 {public static void main (String args[]) throws Exception {//FINAL
int count = 5;
Final int phasetoterminate = 3; Final Phaser Phaser = new Phaser (count) {@Override protected boolean onadvance (int phase, int
registeredparties) {System.out.println ("= = =" + phase + "= ="); return phase = = Phasetoterminate | |
registeredparties = 0;
}
};
for (int i = 0; i < count; i++) {System.out.println ("Starting Thread, ID:" + i);
Final thread thread = new Thread (new Task (I, Phaser));
Thread.Start ();
}//Phaser.register ();
while (!phaser.isterminated ()) {phaser.arriveandawaitadvance ();
} System.out.println ("Done");
}
public static class Task implements Runnable {//private final int id;
Private final Phaser Phaser;
public Task (int ID, Phaser phaser) {this.id = ID;
This.phaser = Phaser;
@Override public void Run () {while (!phaser.isterminated ()) {
try {thread.sleep (500); The catch (Interruptedexception e) {//NOP} System.out.println ("I
n Task.run (), Phase: "+ phaser.getphase () +", ID: "+ this.id);
Phaser.arriveandawaitadvance (); }
}
}
}
If you want the main thread to terminate after the end of a particular phase, you can call the following methods in the main thread:
public static void Awaitphase (Phaser phaser, int phase) {
int p = phaser.register ();//assumes caller not already Reg istered while
(P < phase) {
if (phaser.isterminated ()) {break
;//... deal with unexpected