目录
一.简介
CyclicBarrier解决了CDL不能重用的问题,但是仍有以下不足:
1)不能动态调整计数器值,假如线程数不足以打破barrier,就只能reset或者多加些线程,在实际运用中显然不现实
2)每次await仅消耗1个计数器值,不够灵活
Phaser就是用来解决这些问题的。Phaser将多个线程协作执行的任务划分为多个阶段,每个阶段都可以有任意个参与者,线程可以随时注册并参与到某个阶段。下面给出一个例子:
import java.util.Random;
import java.util.concurrent.Phaser;
public class PhaserTest {
private static Phaser phaser = new Phaser(3);
public static void testMethod(){
while(true){
System.out.println(Thread.currentThread().getName()+",Phase:"+phaser.getPhase()+",now:"+System.currentTimeMillis());
try {
Thread.sleep(new Random().nextInt(5)*1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
phaser.arriveAndAwaitAdvance();
System.out.println(Thread.currentThread().getName()+",Phase:"+phaser.getPhase()+",now:"+System.currentTimeMillis());
}
}
public static void main(String args[]) {
Thread a = new Thread(()->testMethod(),"A");
a.start();
Thread b = new Thread(()->testMethod(),"B");
b.start();
Thread c = new Thread(()->testMethod(),"C");
c.start();
}
}
输出如下:
A,Phase:0,now:1550904587079
B,Phase:0,now:1550904587080
C,Phase:0,now:1550904587080
A,Phase:1,now:1550904591081
B,Phase:1,now:1550904591081
C,Phase:1,now:1550904591081
B,Phase:1,now:1550904591082
A,Phase:1,now:1550904591081
C,Phase:1,now:1550904591082
...
可以看到,每次输出时,三个线程的时间戳都是一样的。显然每调用一次arriveAndAwaitAdvance,phase值就会加1,代表进入了新一轮同步。
二.构造方法
Phaser有多个构造方法,不过实际执行的是同一个:
public Phaser(Phaser parent, int parties) {
if (parties >>> PARTIES_SHIFT != 0)
throw new IllegalArgumentException("Illegal number of parties");
int phase = 0;
this.parent = parent;
if (parent != null) {
final Phaser root = parent.root;
this.root = root;
this.evenQ = root.evenQ;
this.oddQ = root.oddQ;
if (parties != 0)
phase = parent.doRegister(1);
}
else {
this.root = this;
this.evenQ = new AtomicReference<QNode>();
this.oddQ = new AtomicReference<QNode>();
}
this.state = (parties == 0) ? (long)EMPTY :
((long)phase << PHASE_SHIFT) |
(