对于Phaser,我回答了几个问题。看到它们可能有助于理解它们的应用程序。它们在底部链接。但是,要了解Phaser的作用以及为什么它有用,重要的是要知道它解决了什么问题。
以下是倒计时闩锁和循环巴里尔的属性
注意:
- 参与方的数量是另一种说法,即不同线程的数量
- 不可重用意味着在重用之前,您必须创建屏障的新实例
- 如果线程可以到达并继续工作而无需等待其他人,或者可以等待所有线程完成,则障碍是可以提前的
倒计时
- 固定的参与方数量
- 不可补发
- 可先得(看可先行必等
latch.countDown();
latch.await();
)
循环巴里耶
- 固定的参与方数量
- 可 重用
- 不可提前
因此,CountdownLatch是不可重用的,您必须每次创建一个新实例,但可以免费使用。CylicBarrier可以重复使用,但所有线程都必须等待各方到达屏障。
相位
- 动态参与方数量
- 可 重用
- 可高级
当一个线程想要被相位器知道时,当线程到达它们调用的屏障时,它们会调用,这里是可以提前的。如果线程想要等待所有已注册的任务完成phaser.register()
phaser.arrive()
phaser.arriveAndAwaitAdvance()
还有一个阶段的概念,在该阶段中,线程可以等待可能尚未完成的其他操作的完成。一旦所有线程到达相位器的屏障,就会创建一个新阶段(增量为1)。
你可以看看我的其他答案,也许会有所帮助:
至少,我认为JavaDoc提供了一个相当清晰的解释。这是一个用于同步一批线程的类,从某种意义上说,您可以使用 a 注册批处理中的每个线程,然后使用 to have them 块,直到批处理中的每个线程都通知了 ,此时任何被阻止的线程都将开始执行。这种等待/通知周期可以根据需要/要求一遍又一遍地重复。Phaser
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();
}
...这与以前相同,只是添加了一个循环,导致任务重复运行。因为每次迭代调用,所以任务线程的执行将同步,使得 task-0 不会开始其第二次迭代,直到所有其他任务都完成其第一次迭代并通知 该任务已准备好开始其第二次迭代。phaser.arriveAndAwaitAdvance()
Phaser
如果您正在运行的任务在执行时间上存在很大差异,并且您希望确保较快的线程不会与较慢的线程不同步,这可能很有用。
对于可能的实际应用程序,请考虑运行单独图形和物理线程的游戏。如果图形线程卡在第 6 帧上,则您不希望物理线程计算第 100 帧的数据,并且使用一种可能的方法可以确保图形和物理线程始终在同一帧上同时工作(并且如果一个线程明显慢于另一个线程,则更快的线程会优雅地产生 CPU 资源,以便希望较慢的线程可以捕获上来更快)。Phaser
-
执行器:如果以递归方式创建任务,如何同步等待所有任务完成? 我的问题与密切相关。正如在那里发布的那样,我希望主线程等到工作队列为空并且所有任务都已完成。但是,在我的情况下,问题是每个任务都可能递归地导致提交新任务进行处理。这使得收
-
关于在对象的构造函数完成之前对对象的引用 你们每个人都知道JMM的这个功能,有时在这个对象的构造函数完成之前,对对象的引用可以接收值。 在 问答中,格雷先生写道: 如果将字段标记为,则构造函数保证作为构造函数的一部分
-
异步通知阻止队列具有可用的项目 我需要一个,当有些人有一个项目要给时,我会得到异步通知。 问题是:有没有更好的方法来做到这一点?我是否犯了一些不可原谅的错误(无论是在并发性/效率和/或代码清理方面)?提前致
-
ConcurrentLinkedQueue$Node 在 remove() 后仍保留在堆中 我有一个多线程应用程序编写和读取并发链接队列,它在概念上用于支持列表/表中的条目。我最初使用 ConcurrentHashMap 来实现这一点,效果很好。一项新要求要求跟踪传入的订单条目,因此可以
-
Java 内存模型:创建最终实例字段的循环参考图是否安全,所有字段都在同一线程中分配? 比我更了解 Java 内存模型的人能否确认我对以下代码已正确同步的理解? 我知道这段代码是正确的,但我还没有完成整个发生 - 在数学之前。我确实发现了两个非正式的引文,表明这是合法的