Java并发包中的Phaser功能强大,灵活的同时,也很复杂,不容易理解,Phaser类似于CyclicBarrier和CountDownLatch。相比于CyclicBarrier, Phaser主要有以下特征
- Phaser不但可以像CyclicBarrier一样,可重复使用,而且能动态变更参与方数量数量,在 CyclicBarrier 中,在创建时,参与方数量是固定的。但是,在Phaser中,可以通过调用register()添加参与方,arriveAndDeregister()方法删除参与方。
- 一个Phaser有一个相关的phrase号,从0开始。当所有注册方都到达一个Phaser时,Phaser进入下一个phrase,phrase号递增1。phrase号的最大值为Integer.MAX_VALUE(private static final int MAX_PHASE= Integer.MAX_VALUE;)。最大值后,相位号以零为起点重新开始。类似赛中的回合制。
- Phaser有一个终止状态。在终止状态下,所有在Phaser上调用的同步方法都会立即返回,而不需要等待预处理
- Phaser类的onAdvance()方法中写代码来指定一个phaser动作让所有注册方到达 phaser 时执行 phaser 动作。可以在个方法里面返回true,让Phaser不再执行。
用途:主要用于将一些并发任务分成若干个步骤
例如一个表的数据存储在三个库中,统计一个字段的数据,可以写三个三个线程从三个库中读,在主线程中phaser.arriveAndAwaitAdvance()方法,等待三个线程执行完后,进行统计。
实例
我们用Phaser模拟一个跑步比赛,选手人数不定,比赛不分轮次,每一轮淘汰跑步时间超过一定时间的选手,直到最后一个胜出为止。
Runner类继承Thread类,代表每一个参赛者,,随机生成一个1到5的整数,,用Thread.sleep()模拟参赛者跑步时长,每一轮都要等所有参赛者都到达后开始,当所有如果用时大于5秒,则淘汰。具体代码:
import java.util.Random;
import java.util.concurrent.Phaser;
public class Runner extends Thread {
private final String name;
private final Phaser phaser;
private static Random rand = new Random();
public Runner(String name, Phaser phaser) {
this.name = name;
this.phaser = phaser;
}
@Override
public void run() {
while (!phaser.isTerminated()) {
try {
phaser.arriveAndAwaitAdvance();
if(phaser.getArrivedParties() == 1) {
System.out.println(String.format("%s win", name));
phaser.arriveAndDeregister();
return;
}
int sleepTime = rand.nextInt(5) + 1;
Thread.sleep(sleepTime * 1000);
System.out.println(String.format("%s run Time:%d", name, sleepTime));
if (sleepTime >= 5) {
phaser.arriveAndDeregister();
System.out.println(String.format("%s run Time:%d out", name, sleepTime));
return;
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
RunnerTest类里实现了Phaser类,重载了onAdvance()方法。
import java.util.concurrent.Phaser;
public class RunnerTest {
public static void main(String[] args) {
final Integer PERSON_COUNT = 3;
Phaser phaser = new Phaser() {
@Override
protected boolean onAdvance(int phase, int parties) {
System.out.println(String.format("%d arrive phase :%d", parties, phase));
if (parties == 1) {
return true;
}
System.out.println("------------------");
return false;
}
};
phaser.bulkRegister(PERSON_COUNT);
for (int i = 0; i < PERSON_COUNT; i++) {
Runner person = new Runner("Runner" + i, phaser);
person.start();
}
}
}
运行结果:
3 arrive phase :0
------------------
Runner1 run Time:1
Runner2 run Time:4
Runner0 run Time:5
2 arrive phase :1
------------------
Runner0 run Time:5 out
Runner1 run Time:4
Runner2 run Time:5
1 arrive phase :2
Runner2 run Time:5 out
Runner1 win