我正在学习Phaser。在这样做的过程中,我遇到了一个问题。下面是我的代码,
public class RunnableTask implements Runnable {
private Phaser phaser;
public RunnableTask(Phaser phaser) {
this.phaser = phaser;
this.phaser.register(); // Question
}
@Override
public void run() {
// this.phaser.register(); // Question
print("After register");
for (int i = 0; i < 2; i++) {
sleep();
print("Before await" + i + ":");
this.phaser.arriveAndAwaitAdvance();
print("After advance" + i + ":");
}
}
private void sleep() {
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private void print(String msg) {
System.out.println(String.format("%s: %s, time=%s, registered=%s, arrived=%s, unarrived=%s, phase=%s.", msg,
Thread.currentThread().getName(), LocalTime.now(), this.phaser.getRegisteredParties(),
this.phaser.getArrivedParties(), this.phaser.getUnarrivedParties(), this.phaser.getPhase()));
}
}
上述样本测试
public class TestPhaser {
public static void main(String[] args) {
Phaser phaser = new Phaser();
RunnableTask task = new RunnableTask(phaser);
Thread t1 = new Thread(task, "t1");
Thread t2 = new Thread(task, "t2");
Thread t3 = new Thread(task, "t3");
t1.start();
t2.start();
t3.start();
}
}
执行上述程序后,输出为:
注册后:t3,时间=22:01:26.636,注册=1,到达=0,未到达=1,阶段=0。
注册后:t2,时间=22:01:26.636,注册=1,到达=0,未到达=1,阶段=0。
注册后:t1,时间=22:01:26.636,注册=1,到达=0,未到达=1,阶段=0。
在等待 0::t3 之前,时间=22:01:28.728,注册=1,到达=0,未到达=1,阶段=0。
在等待 0::t2 之前,时间=22:01:28.728,注册=1,到达=0,未到达=1,阶段=0。
在等待 0::t1 之前,时间=22:01:28.728,注册=1,到达=0,未到达=1,阶段=0。
在提前 0::t1 之后,时间=22:01:28.728,注册=1,到达=0,未到达=1,阶段=3。
提前0::t2后,时间=22:01:28.728,注册=1,到达=0,未到达=1,阶段=3。
在提前 0::t3 之后,时间=22:01:28.729,注册=1,到达=0,未到达=1,阶段=3。
在等待 1::t2 之前,时间=22:01:30.730,注册=1,到达=0,未到达=1,阶段=3。
在等待 1::t3 之前,时间=22:01:30.730,注册=1,到达=0,未到达=1,阶段=3。
在提前 1::t2 之后,时间=22:01:30.730,注册=1,到达=0,未到达=1,阶段=4。
在提前 1::t3 之后,时间=22:01:30.732,注册=1,到达=0,未到达=1,阶段=5。
在等待 1::t1 之前,时间=22:01:30.730,注册=1,到达=0,未到达=1,阶段=3。
在提前 1::t1 之后,时间=22:01:30.732,注册=1,到达=0,未到达=1,阶段=6。
您可以看到这里有很多差异。线程不是按顺序推进的。此外,很少有阶段丢失或/和不按顺序排列。
当我将代码 this.phaser.register() 从构造函数移动到 run 方法的开头时,输出为:
注册后:t1,时间=22:10:58.230,注册=3,到达=0,未到达=3,阶段=0。
注册后:t3,时间=22:10:58.230,注册=3,到达=0,未到达=3,阶段=0。
注册后:t2,时间=22:10:58.230,注册=3,到达=0,未到达=3,阶段=0。
在等待 0::t2 之前,时间=22:11:00.314,注册=3,到达=0,未到达=3,阶段=0。
在等待 0::t1 之前,时间=22:11:00.314,注册=3,到达=0,未到达=3,阶段=0。
在等待 0::t3 之前,时间=22:11:00.314,注册=3,到达=0,未到达=3,阶段=0。
提前0::t2后,时间=22:11:00.315,注册=3,到达=0,未到达=3,阶段=1。
提前0::t3后,时间=22:11:00.315,注册=3,到达=0,未到达=3,阶段=1。
提前0::t1后,时间=22:11:00.315,注册=3,到达=0,未到达=3,阶段=1。
在等待 1::t1 之前,时间=22:11:02.319,注册=3,到达=0,未到达=3,阶段=1。
在等待 1::t2 之前,时间=22:11:02.319,注册=3,到达=0,未到达=3,阶段=1。
在等待 1::t3 之前,时间=22:11:02.319,注册=3,到达=0,未到达=3,阶段=1。
在提前 1::t3 之后,时间=22:11:02.320,注册=3,到达=0,未到达=3,阶段=2。
在提前 1::t2 之后,时间=22:11:02.320,注册=3,到达=0,未到达=3,阶段=2。
在提前 1::t1 之后,时间=22:11:02.321,注册=3,到达=0,未到达=3,阶段=2。
这看起来好多了,线程执行和阶段是按顺序排列的。
以下是我的问题:
1) 为什么在 Runnable 的构造函数中注册方时会有很多差异?
2) 在第二个结果中,到达和未到达的统计数据在每个阶段都为零(不正确)。那么,如何为他们获取正确的数字呢?
任何帮助表示赞赏。