Jas*_*n S 16 java concurrency phaser
这个问题是两年前提出的,但它提到的资源要么不是很有用(恕我直言),要么链接不再有效.
必须要有一些很好的教程才能理解Phaser.我已经阅读了javadoc,但是我的眼睛茫然,因为为了真正理解javadoc你必须知道如何使用这些类.
有人有什么建议吗?
Joh*_*int 46
对于Phaser,我回答了几个问题.看到它们可能有助于理解它们的应用.它们在底部相连.但要了解Phaser的作用以及为什么它有用,重要的是要知道它解决了什么.
以下是CountdownLatch和CyclicBarrier的属性
注意:
CountdownLatch
latch.countDown(); 推进的
latch.await(); 必须等待)的CyclicBarrier
因此CountdownLatch不可重复使用,您必须每次都创建一个新实例,但是可以使用.CylicBarrier可以重复使用,但所有线程必须等待每一方到达屏障.
移相器
当一个线程想要被Phaser知道phaser.register()时,当线程到达它们调用的屏障时,它们就会调用phaser.arrive() ,这里它是可推进的.如果线程想要等待所有已注册的任务完成phaser.arriveAndAwaitAdvance()
还有一个阶段的概念,其中线程可以在完成可能尚未完成的其他操作时等待.一旦所有线程到达移相器的障碍,就会创建一个新阶段(增量为1).
你可以看看我的其他答案,也许它会有所帮助:
Java ExecutorService:awaitTermination所有递归创建的任务
对于Phaser至少,我认为的JavaDoc提供了一个相当明确的解释.这是一个用于同步一批线程的类,在这个意义上你可以用a注册批处理中的每个线程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();
}
Run Code Online (Sandbox Code Playgroud)
这将设置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();
}
Run Code Online (Sandbox Code Playgroud)
...这与之前相同,只是添加了一个循环,导致任务重复运行.因为每次迭代调用phaser.arriveAndAwaitAdvance()任务线程的执行将被同步,使得task-0不会开始其第二次迭代,直到每个其他任务完成其第一次迭代并且通知Phaser它已准备好开始其第二次迭代.
如果您运行的任务在执行时花费的时间差异很大,并且您希望确保更快的线程不会与较慢的线程不同步,则这可能很有用.
对于可能的实际应用程序,请考虑运行单独的图形和物理线程的游戏.如果图形线程卡在第6帧上,您不希望拥有帧100的物理线程计算数据,并且使用a Phaser是一种可能的方法来确保图形和物理线程始终在同一帧上工作时间(并且如果一个线程比另一个线程明显慢,则速度更快的线程优雅地产生CPU资源,以便更慢的线程可以更快地赶上).
| 归档时间: |
|
| 查看次数: |
5500 次 |
| 最近记录: |