前言
目前正在出一个Java多线程专题
长期系列教程,从入门到进阶含源码解读
, 篇幅会较多, 喜欢的话,给个关注❤️ ~
Java提供了一些非常好用的并发工具类,不需要我们重复造轮子,本节我们讲解Phaser
,一起来看下吧~
Phaser
Phaser又称“阶段器”,用来解决多线程分阶段任务的场景。它与CountDownLatch和CyclicBarrier类似,都是等待一组线程完成工作后再执行下一步。但CountDownLatch和CyclicBarrier中不能动态的配置parties,而Phaser可以动态注册,相对而言更加的灵活。
常用方法
-
int register()
动态添加一个parties -
int bulkRegister(int parties)
动态添加多个parties -
int getRegisteredParties()
获取当前的parties数 -
int arriveAndAwaitAdvance()
到达并等待其他线程到达 -
int arriveAndDeregister()
到达并注销该parties,这个方法不会使线程阻塞 -
int arrive()
到达,但不会使线程阻塞 -
int awaitAdvance(int phase)
等待前行,可阻塞也可不阻塞,判断条件为phase,如果相等则阻塞 -
int awaitAdvanceInterruptibly(int phase)
该方法与awaitAdvance类似,唯一不一样的就是它可以进行打断。 -
int awaitAdvanceInterruptibly(int phase, long timeout, TimeUnit unit)
同上 -
int getArrivedParties()
获取当前到达的parties数 -
int getUnarrivedParties()
获取当前未到达的parties数 -
int getPhase()
获取当前属于第几阶段,默认从0开始,最大为integer的最大值 -
boolean isTerminated()
判断当前phaser是否关闭 -
void forceTermination()
强制关闭当前phaser
示例
基本上把能用到的方法都给大家介绍了,下面我们通过一个例子实际体验一下:
public class PhaserTest {
public static void main(String[] args) {
Phaser phaser = new Phaser(10);
for (int i=0; i<10; i++){
new Thread(() -> {
try {
long millis = System.currentTimeMillis();
System.out.println(millis + "--1-->当前处于"+phaser.getPhase()+"阶段");
Thread.sleep(1000);
// wait
phaser.arriveAndAwaitAdvance();
System.out.println(millis + "---2--->当前处于"+phaser.getPhase()+"阶段");
Thread.sleep(1000);
// wait
phaser.arriveAndAwaitAdvance();
System.out.println(millis + "---3--->当前处于"+phaser.getPhase()+"阶段");
Thread.sleep(1000);
// wait
phaser.arriveAndAwaitAdvance();
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
}
System.out.println("主线程");
}
}
实际输出:
1659925927951--1-->当前处于0阶段
主线程
1659925927951--1-->当前处于0阶段
1659925927951--1-->当前处于0阶段
1659925927950--1-->当前处于0阶段
1659925927951--1-->当前处于0阶段
1659925927951--1-->当前处于0阶段
1659925927951--1-->当前处于0阶段
1659925927951--1-->当前处于0阶段
1659925927950--1-->当前处于0阶段
1659925927951--1-->当前处于0阶段
1659925927951---2--->当前处于1阶段
1659925927950---2--->当前处于1阶段
1659925927951---2--->当前处于1阶段
1659925927950---2--->当前处于1阶段
1659925927951---2--->当前处于1阶段
1659925927951---2--->当前处于1阶段
1659925927951---2--->当前处于1阶段
1659925927951---2--->当前处于1阶段
1659925927951---2--->当前处于1阶段
1659925927951---2--->当前处于1阶段
1659925927951---3--->当前处于2阶段
1659925927951---3--->当前处于2阶段
1659925927950---3--->当前处于2阶段
1659925927951---3--->当前处于2阶段
1659925927950---3--->当前处于2阶段
1659925927951---3--->当前处于2阶段
1659925927951---3--->当前处于2阶段
1659925927951---3--->当前处于2阶段
1659925927951---3--->当前处于2阶段
1659925927951---3--->当前处于2阶段
可以看出并不会造成主线程的阻塞,任务也是分阶段去完成的, 其它方法就不一一演示了,大家可以自行操作一下
结束语
本节主要讲解它的一个使用,有兴趣的同学可以看一下它的底层源码实现,相对于前两个要复杂一点,这里就不过多介绍。下一节,给大家讲下Fork/Join
框架,关注我,不迷路 ~