必须有一些好的教程才能理解Phaser
。我已经阅读了javadoc,但是我的眼睛茫然,因为为了真正理解javadoc,你必须知道应该如何使用这些类。
有人有任何建议吗?
答案 0 :(得分:45)
对于Phaser,我已经回答了几个问题。看到它们可能有助于理解它们的应用。它们在底部相连。但要了解Phaser的作用以及为什么它有用,重要的是要知道它解决了什么。
以下是CountdownLatch和CyclicBarrier的属性
注意:
<强> CountdownLatch 强>
latch.countDown();
可推进
latch.await();
必须等待)<强> 的CyclicBarrier 强>
因此CountdownLatch不可重复使用,您必须每次都创建一个新实例,但是可以使用。可以重复使用CylicBarrier,但所有线程必须等待每一方到达屏障。
<强> 移相 强>
当一个线程想要被Phaser知道时,当线程到达屏障时,他们调用phaser.register()
,他们调用phaser.arrive()
,这里是可推进的。如果线程想要等待所有已注册的任务完成phaser.arriveAndAwaitAdvance()
还有一个阶段的概念,其中线程可以在完成其他可能尚未完成的操作时等待。一旦所有线程到达移相器的障碍,就会创建一个新阶段(增量为1)。
你可以看看我的其他答案,也许会有所帮助:
Java ExecutorService: awaitTermination of all recursively created tasks
答案 1 :(得分:5)
至少对于Phaser
,我认为JavaDoc提供了一个相当清晰的解释。这是一个用于同步一批线程的类,在这种意义上,您可以使用Phaser
注册批处理中的每个线程,然后使用Phaser
阻止它们直到每个线程在批处理中已通知Phaser
,此时任何被阻塞的线程将开始执行。该等待/通知周期可以根据需要/要求一遍又一遍地重复。
他们的示例代码给出了一个合理的例子(虽然我非常不喜欢他们的2字符缩进样式):
void runTasks(List<Runnable> tasks) {
final Phaser phaser = new Phaser(1); // "1" to register self
// create and start threads
for (final Runnable task : tasks) {
phaser.register();
new Thread() {
public void run() {
phaser.arriveAndAwaitAdvance(); // await all creation
task.run();
}
}.start();
}
// allow threads to start and deregister self
phaser.arriveAndDeregister();
}
这会设置一个Phaser
,其注册次数为tasks.size() + 1
,并且每个任务都会创建一个新的Thread
,它会阻止Phaser
的下一个进度(即记录tasks.size() + 1
到达的时间,然后运行其相关任务。创建的每个Thread
也会立即启动,因此Phaser
会在循环中出现tasks.size()
到达的记录。
对phaser.arriveAndDeregister()
的最后一次调用将记录最终到达,并减少注册次数,使其现在等于tasks.size()
。这会导致Phaser
前进,这实际上允许所有任务同时开始运行。这可以通过以下方式重复:
void runTasks(List<Runnable> tasks) {
final Phaser phaser = new Phaser(1); // "1" to register self
// create and start threads
for (final Runnable task : tasks) {
phaser.register();
new Thread() {
public void run() {
while (true) {
phaser.arriveAndAwaitAdvance(); // await all creation
task.run();
}
}
}.start();
}
// allow threads to start and deregister self
phaser.arriveAndDeregister();
}
...这与之前相同,只是添加了一个循环,导致任务重复运行。因为每次迭代都会调用phaser.arriveAndAwaitAdvance()
,所以任务线程的执行将被同步,以便task-0不会开始第二次迭代,直到每个其他任务完成第一次迭代并通知已准备好的Phaser
开始第二次迭代。
如果您运行的任务在执行时花费的时间差异很大,并且您希望确保更快的线程不会与较慢的线程不同步,那么这可能很有用。
对于可能的实际应用程序,请考虑运行单独的图形和物理线程的游戏。如果图形线程卡在第6帧上,您不希望拥有第100帧的物理线程计算数据,并且使用Phaser
是一种可能的方法来确保图形和物理线程始终在相同的帧同时(并且如果一个线程明显慢于另一个线程,则更快的线程优雅地产生CPU资源,以便更慢的线程可以更快地赶上)。
答案 2 :(得分:2)
Phaser在功能上与CyclicBarrier和CountDownLatch有些相似,但它提供了比两者更多的灵活性。
在CyclicBarrier中,我们曾经在构造函数中注册方,但Phaser在任何时候都为我们提供了注册和取消注册方的灵活性。 对于注册方,我们可以使用以下任何一种方式 -
对于 deRegistering 方,我们可以使用 -
注册 -
添加/注册此移相器的新未命名方。它返回
如果onAdvance()方法的调用正在进行,则返回此方法可能等待其完成。
如果此移相器具有父级,并且此移相器没有注册方,则此子移相器也会向其父级注册。
演示使用Phaser&gt;
import java.util.concurrent.Phaser;
public class PhaserTest {
public static void main(String[] args) {
/*Creates a new phaser with 1 registered unArrived parties
* and initial phase number is 0
*/
Phaser phaser=new Phaser(1);
System.out.println("new phaser with 1 registered unArrived parties"
+ " created and initial phase number is 0 ");
//Create 3 threads
Thread thread1=new Thread(new MyRunnable(phaser,"first"),"Thread-1");
Thread thread2=new Thread(new MyRunnable(phaser,"second"),"Thread-2");
Thread thread3=new Thread(new MyRunnable(phaser,"third"),"Thread-3");
System.out.println("\n--------Phaser has started---------------");
//Start 3 threads
thread1.start();
thread2.start();
thread3.start();
//get current phase
int currentPhase=phaser.getPhase();
/*arriveAndAwaitAdvance() will cause thread to wait until current phase
* has been completed i.e. until all registered threads
* call arriveAndAwaitAdvance()
*/
phaser.arriveAndAwaitAdvance();
System.out.println("------Phase-"+currentPhase+" has been COMPLETED----------");
//------NEXT PHASE BEGINS------
currentPhase=phaser.getPhase();
phaser.arriveAndAwaitAdvance();
System.out.println("------Phase-"+currentPhase+" has been COMPLETED----------");
/* current thread Arrives and deRegisters from phaser.
* DeRegistration reduces the number of parties that may
* be required to advance in future phases.
*/
phaser.arriveAndDeregister();
//check whether phaser has been terminated or not.
if(phaser.isTerminated())
System.out.println("\nPhaser has been terminated");
}
}
class MyRunnable implements Runnable{
Phaser phaser;
MyRunnable(Phaser phaser,String name){
this.phaser=phaser;
this.phaser.register(); //Registers/Add a new unArrived party to this phaser.
System.out.println(name +" - New unarrived party has "
+ "been registered with phaser");
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName() +
" - party has arrived and is working in "
+ "Phase-"+phaser.getPhase());
phaser.arriveAndAwaitAdvance();
//Sleep has been used for formatting output
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//------NEXT PHASE BEGINS------
System.out.println(Thread.currentThread().getName() +
" - party has arrived and is working in "
+ "Phase-"+phaser.getPhase());
phaser.arriveAndAwaitAdvance();
phaser.arriveAndDeregister();
}
}
bulkRegister -
为此移相器添加多个新的未获得方的人。它返回
如果onAdvance()方法的调用正在进行,则返回此方法可能等待其完成。
arriveAndDeregister - 的 当前线程(Party)从移相器到达和取消注册。 DeRegistration减少了将来可能需要进入下一阶段的各方数量。
如果此移相器具有父级,并且此移相器没有注册方,则此子移相器也会向其父级注册。 计划展示父母和子女Phaser
import java.util.concurrent.Phaser;
public class PhaserParentChildTest {
public static void main(String[] args) {
/*
* Creates a new phaser with no registered unArrived parties.
*/
Phaser parentPhaser = new Phaser();
/*
* Creates a new phaser with the given parent &
* no registered unArrived parties.
*/
Phaser childPhaser = new Phaser(parentPhaser,0);
childPhaser.register();
System.out.println("parentPhaser isTerminated : "+parentPhaser.isTerminated());
System.out.println("childPhaser isTerminated : "+childPhaser.isTerminated());
childPhaser.arriveAndDeregister();
System.out.println("\n--childPhaser has called arriveAndDeregister()-- \n");
System.out.println("parentPhaser isTerminated : "+parentPhaser.isTerminated());
System.out.println("childPhaser isTerminated : "+childPhaser.isTerminated());
}
}
在http://www.javamadesoeasy.com/2015/03/phaser-in-java_21.html
上阅读有关Phaser的更多信息