我正在学习 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();
}
}
执行上述程序后,输出为:
After register: t3, time=22:01:26.636, registered=1, arrived=0, unarrived=1, phase=0.
After register: t2, time=22:01:26.636, registered=1, arrived=0, unarrived=1, phase=0.
After register: t1, time=22:01:26.636, registered=1, arrived=0, unarrived=1, phase=0.
Before await 0:: t3, time=22:01:28.728, registered=1, arrived=0, unarrived=1, phase=0.
Before await 0:: t2, time=22:01:28.728, registered=1, arrived=0, unarrived=1, phase=0.
Before await 0:: t1, time=22:01:28.728, registered=1, arrived=0, unarrived=1, phase=0.
After advance 0:: t1, time=22:01:28.728, registered=1, arrived=0, unarrived=1, phase=3.
After advance 0:: t2, time=22:01:28.728, registered=1, arrived=0, unarrived=1, phase=3.
After advance 0:: t3, time=22:01:28.729, registered=1, arrived=0, unarrived=1, phase=3.
Before await 1:: t2, time=22:01:30.730, registered=1, arrived=0, unarrived=1, phase=3.
Before await 1:: t3, time=22:01:30.730, registered=1, arrived=0, unarrived=1, phase=3.
After advance 1:: t2, time=22:01:30.730, registered=1, arrived=0, unarrived=1, phase=4.
After advance 1:: t3, time=22:01:30.732, registered=1, arrived=0, unarrived=1, phase=5.
Before await 1:: t1, time=22:01:30.730, registered=1, arrived=0, unarrived=1, phase=3.
After advance 1:: t1, time=22:01:30.732, registered=1, arrived=0, unarrived=1, phase=6.
您可以看到这里有很多差异。线程不按顺序前进。此外,有几个阶段缺失或/且不按顺序排列。
当我将代码行 this.phaser.register() 从构造函数移动到 run 方法的开头时,输出为:
After register: t1, time=22:10:58.230, registered=3, arrived=0, unarrived=3, phase=0.
After register: t3, time=22:10:58.230, registered=3, arrived=0, unarrived=3, phase=0.
After register: t2, time=22:10:58.230, registered=3, arrived=0, unarrived=3, phase=0.
Before await 0:: t2, time=22:11:00.314, registered=3, arrived=0, unarrived=3, phase=0.
Before await 0:: t1, time=22:11:00.314, registered=3, arrived=0, unarrived=3, phase=0.
Before await 0:: t3, time=22:11:00.314, registered=3, arrived=0, unarrived=3, phase=0.
After advance 0:: t2, time=22:11:00.315, registered=3, arrived=0, unarrived=3, phase=1.
After advance 0:: t3, time=22:11:00.315, registered=3, arrived=0, unarrived=3, phase=1.
After advance 0:: t1, time=22:11:00.315, registered=3, arrived=0, unarrived=3, phase=1.
Before await 1:: t1, time=22:11:02.319, registered=3, arrived=0, unarrived=3, phase=1.
Before await 1:: t2, time=22:11:02.319, registered=3, arrived=0, unarrived=3, phase=1.
Before await 1:: t3, time=22:11:02.319, registered=3, arrived=0, unarrived=3, phase=1.
After advance 1:: t3, time=22:11:02.320, registered=3, arrived=0, unarrived=3, phase=2.
After advance 1:: t2, time=22:11:02.320, registered=3, arrived=0, unarrived=3, phase=2.
After advance 1:: t1, time=22:11:02.321, registered=3, arrived=0, unarrived=3, phase=2.
线程执行和阶段按顺序排列看起来要好得多。
这是我的问题:
1)为什么在Runnable的构造函数中注册各方时会出现很多差异?
2) 在第二个结果中,每个阶段到达和未到达的统计数据均为零(不正确)。那么,如何获得它们的正确数字呢?
感谢任何帮助。
最佳答案
在第一个示例“在构造函数中创建 Phaser”中,您仅向 Phaser 注册一个线程。您必须创建三个任务,才能在 Phaser 中注册三个线程。
这样修改代码,就可以了。 (不要忘记从代码中删除初始 RunnableTask task = new RunnableTask(phaser); )
Thread t1 = new Thread(new RunnableTask(phaser), "t1");
Thread t2 = new Thread(new RunnableTask(phaser), "t2");
Thread t3 = new Thread(new RunnableTask(phaser), "t3");
在第二个示例中,您在所有线程中等待了 2 秒,这是准确的,所有线程几乎同时到达并等待,像这样更改您的 sleep 方法以引入一些不同的等待,以便线程看到一些到达和未到达线程
private void sleep() {
try {
Random r = new Random();
TimeUnit.SECONDS.sleep(r.nextInt(5));
} catch(InterruptedException e) {
e.printStackTrace();
}
}
你的第二个例子有效,但它不正确。它有效只是因为你在 run 方法开始时有 sleep ,所以所有线程在你调用 Phaser 上的到达和提前方法之前都 catch 在 Phaser 中注册。 如果您要删除 sleep ,那么在调用此线路后
t1.start();
T1 run 方法将被运行,并且 t1 线程将被注册到移相器中。那么可能会在线程 t2 和 t3 启动并注册到移相器中之前调用 t1 run 方法中的 this.phaser.arriveAndAwaitAdvance() ,因此移相器不会等待它们。
您应该在任务的构造函数中或在启动线程之前调用的方法中注册到phaser。
关于java - 将线程注册到 Phaser,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53474375/