Для Phaser
, по крайней мере, я думаю, что JavaDoc предлагает довольно четкое объяснение. Это класс, который вы будете использовать для синхронизации пакета потоков, в том смысле, что вы можете зарегистрировать каждый поток в пакете с помощью Phaser
, а затем использовать Phaser
, чтобы блокировать их, пока каждый поток в пакете не получит уведомил 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() {
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()
, выполнение потоков задачи будет синхронизировано таким образом, что задача-0 не начнет свою вторую итерацию, пока каждая другая задача не завершит свою первую итерацию и не уведомит Phaser
, который готов начать свою вторую итерация.
Это может быть полезно, если выполняемые вами задачи сильно различаются по времени, которое они затрачивают на выполнение, и если вы хотите убедиться, что более быстрые потоки не синхронизируются с более медленными.
В качестве возможного реального приложения можно рассмотреть игру, в которой используются отдельные графические и физические потоки. Вы не хотите, чтобы физический поток вычислял данные для кадра 100, если графический поток застрял на кадре 6, и использование Phaser
является одним из возможных подходов к обеспечению того, чтобы графические и физические потоки всегда работали на одном кадре. в то же время (а также, что, если один поток значительно медленнее другого, более быстрый поток изящно отдает ресурсы ЦП, так что, надеюсь, более медленный поток сможет быстрее его догнать).