目录
Phaser的onAdvance方法
在阶段转变时,即上一阶段结束后,下一阶段开始前,会自动调用onAdvance方法。如果阶段继续执行则返回false,如果Phaser准备进入终止状态,则返回true。
Phaser原逻辑是判断 参与者数量==0。但我们也可以继承Phaser类,通过重写onAdvance方法来自定义相关的控制以及额外的逻辑。
案例说明
案例模拟一场考试,它分3轮答题,每轮答题都需要等待所有学生完成上一轮的问题才开始进行。
一、主程序
程序创建了5个学生,参与答题。
package xyz.jangle.thread.test.n3_6.phaser;
import java.util.concurrent.Phaser;
/**
* Phaser DEMO,本案例模拟一场考试。
* 它总共进行3轮答题,每一轮都要等所有学生答题完成后,再进入下一轮答题。
* @author jangle
* @email jangle@jangle.xyz
* @time 2020年8月12日 下午4:06:42
*
*/
public class M {
public static void main(String[] args) {
Phaser phaser = new MyPhaser();
Student[] students = new Student[5];
for (int i = 0; i < students.length; i++) {
students[i] = new Student(phaser);
phaser.register();
}
Thread[] threads = new Thread[students.length];
for (int i = 0; i < threads.length; i++) {
threads[i] = new Thread(students[i]);
threads[i].start();
}
for (int i = 0; i < threads.length; i++) {
try {
threads[i].join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("Main: 考试结束 phaser终止:"+phaser.isTerminated());
}
}
二、学生类(答题)
模拟考试答题,通过phaser进行每一轮的同步。
package xyz.jangle.thread.test.n3_6.phaser;
import java.util.Date;
import java.util.concurrent.Phaser;
import java.util.concurrent.TimeUnit;
/**
* 创建学生类,模拟考试答题,通过phaser进行每一轮的同步。
* @author jangle
* @email jangle@jangle.xyz
* @time 2020年8月12日 下午3:53:17
*
*/
public class Student implements Runnable {
private Phaser phaser;
public Student(Phaser phaser) {
super();
this.phaser = phaser;
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + ",抵达考场," + new Date());
phaser.arriveAndAwaitAdvance();
System.out.println(Thread.currentThread().getName() + ",进行第一轮答题" + new Date());
doExercise1();
System.out.println(Thread.currentThread().getName() + ",完成第一轮答题,等待大家答完" + new Date());
phaser.arriveAndAwaitAdvance();
System.out.println(Thread.currentThread().getName() + ",开始第二轮答题" + new Date());
doExercise2();
System.out.println(Thread.currentThread().getName() + ",完成第二轮答题,等待大家答完" + new Date());
phaser.arriveAndAwaitAdvance();
System.out.println(Thread.currentThread().getName() + ",开始第三轮答题" + new Date());
doExericise3();
System.out.println(Thread.currentThread().getName() + ",完成第三轮答题,等待大家答完" + new Date());
phaser.arriveAndAwaitAdvance();
}
private void doExericise3() {
doExercise1();
}
private void doExercise2() {
doExercise1();
}
private void doExercise1() {
try {
TimeUnit.SECONDS.sleep((long) (Math.random() * 10));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
三、自定义的MyPhaser
继承自Phaser,并重写onAdvance方法,实现自定义的干预。
package xyz.jangle.thread.test.n3_6.phaser;
import java.util.concurrent.Phaser;
/**
* 继承Phaser,重写onAdvance方法,进行自定义操作。
* (自定义每个阶段转变时所要进行的干预动作。例:阶段1完成后 -> 阶段2开始前)
* @author jangle
* @email jangle@jangle.xyz
* @time 2020年8月12日 下午3:27:58
*
*/
public class MyPhaser extends Phaser {
@Override
protected boolean onAdvance(int phase, int registeredParties) {
// 此处如果返回true会让phaser进入终止状态。
switch (phase) {
case 0:
return studentsArrived();
case 1:
return finishFirstExercise();
case 2:
return finishSecondExercise();
case 3:
return finishExam();
default:
return true;
}
}
private boolean finishExam() {
System.out.println("第三轮答题结束,考试结束。");
return true;
}
private boolean finishSecondExercise() {
System.out.println("所有学生完成第二轮答题,准备进入第三轮答题。");
return false;
}
private boolean finishFirstExercise() {
System.out.println("所有学生完成第一轮答题。准备进入第二轮答题。");
return false;
}
private boolean studentsArrived() {
System.out.println("学生全部抵达考场,学生人数"+getRegisteredParties()+"人");
return false;
}
}
四、执行结果
Thread-2,抵达考场,Wed Aug 12 16:14:02 CST 2020
Thread-1,抵达考场,Wed Aug 12 16:14:02 CST 2020
Thread-4,抵达考场,Wed Aug 12 16:14:02 CST 2020
Thread-0,抵达考场,Wed Aug 12 16:14:02 CST 2020
Thread-3,抵达考场,Wed Aug 12 16:14:02 CST 2020
学生全部抵达考场,学生人数5人
Thread-3,进行第一轮答题Wed Aug 12 16:14:02 CST 2020
Thread-1,进行第一轮答题Wed Aug 12 16:14:02 CST 2020
Thread-2,进行第一轮答题Wed Aug 12 16:14:02 CST 2020
Thread-0,进行第一轮答题Wed Aug 12 16:14:02 CST 2020
Thread-4,进行第一轮答题Wed Aug 12 16:14:02 CST 2020
Thread-2,完成第一轮答题,等待大家答完Wed Aug 12 16:14:08 CST 2020
Thread-1,完成第一轮答题,等待大家答完Wed Aug 12 16:14:09 CST 2020
Thread-4,完成第一轮答题,等待大家答完Wed Aug 12 16:14:10 CST 2020
Thread-3,完成第一轮答题,等待大家答完Wed Aug 12 16:14:10 CST 2020
Thread-0,完成第一轮答题,等待大家答完Wed Aug 12 16:14:10 CST 2020
所有学生完成第一轮答题。准备进入第二轮答题。
Thread-0,开始第二轮答题Wed Aug 12 16:14:10 CST 2020
Thread-3,开始第二轮答题Wed Aug 12 16:14:10 CST 2020
Thread-1,开始第二轮答题Wed Aug 12 16:14:10 CST 2020
Thread-2,开始第二轮答题Wed Aug 12 16:14:10 CST 2020
Thread-4,开始第二轮答题Wed Aug 12 16:14:10 CST 2020
Thread-3,完成第二轮答题,等待大家答完Wed Aug 12 16:14:11 CST 2020
Thread-4,完成第二轮答题,等待大家答完Wed Aug 12 16:14:11 CST 2020
Thread-2,完成第二轮答题,等待大家答完Wed Aug 12 16:14:18 CST 2020
Thread-0,完成第二轮答题,等待大家答完Wed Aug 12 16:14:19 CST 2020
Thread-1,完成第二轮答题,等待大家答完Wed Aug 12 16:14:19 CST 2020
所有学生完成第二轮答题,准备进入第三轮答题。
Thread-1,开始第三轮答题Wed Aug 12 16:14:19 CST 2020
Thread-4,开始第三轮答题Wed Aug 12 16:14:19 CST 2020
Thread-2,开始第三轮答题Wed Aug 12 16:14:19 CST 2020
Thread-0,开始第三轮答题Wed Aug 12 16:14:19 CST 2020
Thread-3,开始第三轮答题Wed Aug 12 16:14:19 CST 2020
Thread-2,完成第三轮答题,等待大家答完Wed Aug 12 16:14:19 CST 2020
Thread-4,完成第三轮答题,等待大家答完Wed Aug 12 16:14:19 CST 2020
Thread-1,完成第三轮答题,等待大家答完Wed Aug 12 16:14:22 CST 2020
Thread-3,完成第三轮答题,等待大家答完Wed Aug 12 16:14:27 CST 2020
Thread-0,完成第三轮答题,等待大家答完Wed Aug 12 16:14:28 CST 2020
第三轮答题结束,考试结束。
Main: 考试结束 phaser终止:true