参考:https://blog.csdn.net/qq_43470725/article/details/120457461
https://blog.csdn.net/liuyu973971883/article/details/107917079
基本使用
在CyclicBarrier、CountDownLatch中,我们使用计数器来控制程序的顺序执行,同样的在Phaser中也是通过计数器来控制。在Phaser中计数器叫做parties, 我们可以通过Phaser的构造函数或者register()方法来注册。
Phaser 最大作用就是:可以重写onAdvance方法,然后自定义分几次(几个阶段)拦截注册数量的线程!!
Phaser的常用方法
1、register方法
int register()
动态添加一个parties
2、bulkRegister方法
int bulkRegister(int parties)
动态添加多个parties
parties:需要添加的个数
3、getRegisteredParties方法
int getRegisteredParties()
获取当前的parties数
4、arriveAndAwaitAdvance方法
int arriveAndAwaitAdvance()
到达并等待其他线程到达
5、arriveAndDeregister方法
int arriveAndDeregister()
到达并注销该parties,这个方法不会使线程阻塞
6、arrive方法
int arrive()
到达,但不会使线程阻塞
7、awaitAdvance方法
int awaitAdvance(int phase)
等待前行,可阻塞也可不阻塞,判断条件为传入的phase是否为当前phaser的phase。如果相等则阻塞,反之不进行阻塞
phase:阶段数值
8、awaitAdvanceInterruptibly方法
int awaitAdvanceInterruptibly(int phase)
int awaitAdvanceInterruptibly(int phase, long timeout, TimeUnit unit)
该方法与awaitAdvance类似,唯一不一样的就是它可以进行打断。
phase:阶段数值
timeout:超时时间
unit:时间单位
9、getArrivedParties方法
int getArrivedParties()
获取当前到达的parties数
10、getUnarrivedParties方法
int getUnarrivedParties()
获取当前未到达的parties数
11、getPhase方法
int getPhase()
获取当前属于第几阶段,默认从0开始,最大为integer的最大值
12、isTerminated方法
boolean isTerminated()
判断当前phaser是否关闭
13、forceTermination方法
void forceTermination()
强制关闭当前phaser
实例:
模拟场景:结婚
好,来看我们自己模拟的一个小例子。模拟了一个结婚的场景,结婚是有好多人要参加的,因此,我们写了一个类Person是一个Runnable可以new出来,扔给Thread去执行,模拟我们每个人要做一些操作,有这么几种方法,arrive()到达、eat()吃、leave()离开、hug()拥抱这么几个。作为一个婚礼来说它会分成好几个阶段,第一阶段大家好都得到齐了,第二个阶段大家开始吃饭, 三阶段大家离开,第四个阶段新郎新娘入洞房,那好,每个人都有这几个方法,在方法的实现里头我就简单的睡了1000个毫秒,我自己写了一个方法,把异常处理写到了方法里了。
在看主程序,一共有五个人参加婚礼了,接下来新郎,新娘参加婚礼,一共七个人。它一start就好调用我们的run()方法,它会挨着牌的调用每一个阶段的方法。那好,我们在每一个阶段是不是得控制人数,第一个阶段得要人到期了才能开始,二阶段所有人都吃饭,三阶段所有人都离开,但是,到了第四阶段进入洞房的时候就不能所有人都干这个事儿了。所以,要模拟一个程序就要把整个过程分好几个阶段,而且每个阶段必须要等这些线程给我干完事儿了你才能进入下一个阶段。
那怎么来模拟过程呢,我定义了一个phaser,我这个phaser是从Phaser这个类继承,重写onAdvance方法,前进,线程抵达这个栅栏的时候,所有的线程都满足了这个第一个栅栏的条件了onAdvance会被自动调用,目前我们有好几个阶段,这个阶段是被写死的,必须是数字0开始,onAdvance会传来两个参数phase是第几个阶段,registeredParties是目前这个阶段有几个人参加,每一个阶段都有一个打印,返回值false,一直到最后一个阶段返回true,所有线程结束,整个栅栏组,Phaser栅栏组就结束了。
我怎么才能让我的线程在一个栅栏面前给停住呢,就是调用phaser.arriveAndAwaitAdvance()这个方法,这个方法的意思是到达等待继续往前走,直到新郎新娘如洞房,其他人不在参与,调用phaser.arriveAndDeregister()
package com.example.dtest.threadTest.use;
import java.util.Random;
import java.util.concurrent.Phaser;
import java.util.concurrent.TimeUnit;
public class PhaserTest {
static Random r = new Random();
static MarriagePhaser phaser = new MarriagePhaser();
static void milliSleep(int milli) {
try {
TimeUnit.MILLISECONDS.sleep(milli);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
phaser.bulkRegister(7);
for(int i=0; i<5; i++) {
new Thread(new Person("p" + i)).start();
}
new Thread(new Person("新郎")).start();
new Thread(new Person("新娘")).start();
}
static class MarriagePhaser extends Phaser {
@Override
protected boolean onAdvance(int phase, int registeredParties) {
switch (phase) {
case 0:
System.out.println("所有人都到齐了!" + registeredParties);
System.out.println();
return false;
case 1:
System.out.println("所有人都吃完了!" + registeredParties);
System.out.println();
return false;
case 2:
System.out.println("所有人都离开了!" + registeredParties);
System.out.println();
return false;
case 3:
System.out.println("婚礼结束!新郎新娘抱抱!" + registeredParties);
return true;
default:
return true;
}
}
}
static class Person implements Runnable {
String name;
public Person(String name) {
this.name = name;
}
public void arrive() {
milliSleep(r.nextInt(1000));
System.out.printf("%s 到达现场!\n", name);
phaser.arriveAndAwaitAdvance();
}
public void eat() {
milliSleep(r.nextInt(1000));
System.out.printf("%s 吃完!\n", name);
phaser.arriveAndAwaitAdvance();
}
public void leave() {
milliSleep(r.nextInt(1000));
System.out.printf("%s 离开!\n", name);
phaser.arriveAndAwaitAdvance();
}
private void hug() {
if(name.equals("新郎") || name.equals("新娘")) {
milliSleep(r.nextInt(1000));
System.out.printf("%s 洞房!\n", name);
phaser.arriveAndAwaitAdvance();
} else {
phaser.arriveAndDeregister();
//phaser.register()
}
}
@Override
public void run() {
arrive();
eat();
leave();
hug();
}
}
}
- 使用int bulkRegister(int parties)方法,注册每个阶段需要等待的线程数量;
- 使用arriveAndAwaitAdvance方法,到达了的线程等待其他线程到达
- 重写 protected boolean onAdvance(int phase, int registeredParties) 方法,自定义所有线程阶段任务