简介
Phaser是一个灵活的线程同步工具,他包含了CyclicBarrier和CountDownLatch的相关功能。
CountDownLatch是先指定N个线程干活,每个线程干完活就减一(countDown()),等待N个线程干完活,await()后面的其他线程才能执行。
CyclicBarrier是先指定需要N个线程,等N个线程到齐了大家同时干活(并发执行),大家在没有全部到齐的情况下同时阻塞在await(),等都到达了await才会同时执行之后的代码。
Phaser正是结合了这二者的特点,可以理解为先指定N个线程等N个线程到齐了开始干第一阶段的活,等第一阶段所有线程干完活了,接着这N个线程继续开始干下一阶段的活,以此类推直至干完业务逻辑了所有阶段的活(当然每个阶段可以干完进入下一个阶段可以踢掉一下不需要的线程,当然也可以全部留下来,不剔除)。
举例
题目:5个学生一起参加考试,一共有三道题,要求所有学生到齐才能开始考试,全部同学都做完第一题,学生才能继续做第二题,全部学生做完了第二题,才能做第三题,所有学生都做完的第三题,考试才结束。分析这个题目:这是一个多线程(5个学生)分阶段问题(考试、第一题做完、第二题做完、第三题做完、结束),所以很适合用Phaser解决这个问题。
代码
MyPhaser类继承自Phaser,重写了每个阶段完成以后的自动调用方法
/**
* @PROJECT_NAME: demo
* @DESCRIPTION: /***
* 下面说说Phaser的高级用法,在Phaser内有2个重要状态,分别是phase和party。
* phase就是阶段,初值为0,当所有的线程执行完本轮任务,同时开始下一轮任务时,
* 意味着当前阶段已结束,进入到下一阶段,phase的值自动加1。
* party就是线程,party=5就意味着Phaser对象当前管理着4个线程。Phaser还有一个重要的方法经常需要被重载,
* 那就是boolean onAdvance(int phase, int registeredParties)方法。此方法有2个作用:
* 1、当每一个阶段执行完毕,此方法会被自动调用,因此,重载此方法写入的代码会在每个阶段执行完毕时执行,
* 相当于CyclicBarrier的barrierAction。
* 2、当此方法返回true时,意味着Phaser被终止,因此可以巧妙的设置此方法的返回值来终止所有线程。
* @AUTHOR:
* @DATE:
*/
public class MyPhaser extends Phaser {
@Override
protected boolean onAdvance(int phase, int registeredParties) { //在每个阶段执行完成后回调的方法,phase是从0开始,每个阶段完成会自增,当返回值为true,phaser终止
switch (phase) {
case 0:
return studentArrived();
case 1:
return finishFirstExercise();
case 2:
return finishSecondExercise();
case 3:
return finishExam();
default:
return true;
}
}
private boolean studentArrived(){
System.out.println("学生准备好了,学生人数:"+getRegisteredParties());
return false;
}
private boolean finishFirstExercise(){
System.out.println("第一题所有学生做完");
return false;
}
private boolean finishSecondExercise(){
System.out.println("第二题所有学生做完");
return false;
}
private boolean finishExam(){
System.out.println("第三题所有学生做完,结束考试");
return true;
}
线程执行业务的具体流程
/**
* @PROJECT_NAME: demo
* @DESCRIPTION: 每个学生的线程执行逻辑,将phaser注册进其中,可控制程序运行逻辑
* arriveAndAwaitAdvance()相当于await(),等待都到达以后
* 回调onAdvance()方法,再执行下一阶段
*/
public class StudentTask implements Runnable{
private Phaser phaser;
public StudentTask(Phaser phaser) {
this.phaser = phaser;
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"到达考试");
phaser.arriveAndAwaitAdvance();
System.out.println(Thread.currentThread().getName()+"做第1题时间...");
doExercise();
System.out.println(Thread.currentThread().getName()+"做第1题完成...");
phaser.arriveAndAwaitAdvance();
System.out.println(Thread.currentThread().getName()+"做第2题时间...");
doExercise();
System.out.println(Thread.currentThread().getName()+"做第2题完成...");
phaser.arriveAndAwaitAdvance();
System.out.println(Thread.currentThread().getName()+"做第3题时间...");
doExercise();
System.out.println(Thread.currentThread().getName()+"做第3题完成...");
phaser.arriveAndAwaitAdvance();
}
private void doExercise() {
long duration = (long)(Math.random()*10);
try {
TimeUnit.SECONDS.sleep(duration);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
主方法
/**
* @PROJECT_NAME: demo
* @DESCRIPTION:
* @AUTHOR: xiangyu.ren
* @DATE: 2022/12/5 10:59
*/
public class Main {
public static void main(String[] args) {
MyPhaser phaser = new MyPhaser();
StudentTask[] studentTask = new StudentTask[5];
for (int i = 0; i < studentTask.length; i++) {
studentTask[i] = new StudentTask(phaser);
phaser.register(); //注册一次表示phaser维护的线程个数
}
Thread[] threads = new Thread[studentTask.length];
for (int i = 0; i < studentTask.length; i++) {
threads[i] = new Thread(studentTask[i], "Student "+i);
threads[i].start();
}
//等待所有线程执行结束
for (int i = 0; i < studentTask.length; i++) {
try {
// 等待线程执行结束
threads[i].join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("Phaser has finished:"+phaser.isTerminated());
}
}