Класс Phaser
public class Phaser extends Object
CyclicBarrier и CountDownLatch, но поддерживающий более гибкое использование. Регистрация. В отличие от других барьеров, количество зарегистрированных участников, синхронизируемых с помощью фазера, может меняться со временем. Задачи можно регистрировать в любой момент (с помощью методов register(), bulkRegister(int) или конструкторов, задающих начальное число участников) и при необходимости отменять регистрацию при любом прибытии (с помощью arriveAndDeregister()). Как и в большинстве базовых средств синхронизации, регистрация и отмена регистрации влияют только на внутренние счетчики; они не ведут никакого дополнительного внутреннего учета, поэтому задачи не могут запросить, зарегистрированы ли они. (Однако такой учет можно добавить, создав подкласс этого класса.)
Синхронизация. Как и CyclicBarrier,
Phaser можно ожидать многократно. Метод arriveAndAwaitAdvance() действует аналогично CyclicBarrier.await. Каждому поколению фазера соответствует номер фазы. Нумерация фаз начинается с нуля и увеличивается, когда все участники прибывают к фазеру, а после достижения
Integer.MAX_VALUE начинается снова с нуля. Номера фаз позволяют независимо управлять действиями при прибытии к фазеру и при ожидании остальных с помощью двух видов методов, которые могут вызываться любым зарегистрированным участником:
-
Прибытие. Методы
arrive()иarriveAndDeregister()регистрируют прибытие. Эти методы не блокируют выполнение, а возвращают соответствующий номер фазы прибытия, то есть номер фазы фазера, к которой относится прибытие. Когда прибывает последний участник для данной фазы, выполняется необязательное действие и фаза сменяется. Эти действия выполняются участником, вызвавшим смену фазы, и задаются переопределением методаonAdvance(int, int), который также управляет завершением. Переопределение этого метода похоже на задание действия для барьера вCyclicBarrier, но обеспечивает большую гибкость. -
Ожидание. Метод
awaitAdvance(int)принимает аргумент с номером фазы прибытия и возвращает управление, когда фазер переходит к другой фазе (или уже находится в ней). В отличие от аналогичных конструкций с использованиемCyclicBarrier, методawaitAdvanceпродолжает ожидание, даже если ожидающий поток прерван. Также доступны версии с поддержкой прерывания и тайм-аута, однако исключения, возникающие при прерываемом ожидании задач или ожидании с тайм-аутом, не изменяют состояние фазера. При необходимости можно выполнить соответствующие действия по восстановлению в обработчиках этих исключений, часто после вызоваforceTermination. Фазеры также могут использоваться задачами, выполняющимися вForkJoinPool. Выполнение гарантируется, если уровень параллелизма пула позволяет разместить максимальное число одновременно заблокированных участников.
Завершение. Фазер может перейти в состояние завершения, которое можно проверить с помощью метода isTerminated(). После завершения все методы синхронизации немедленно возвращают управление, не дожидаясь смены фазы, о чем свидетельствует отрицательное возвращаемое значение. Аналогичным образом попытки регистрации после завершения не оказывают никакого эффекта. Завершение запускается, когда вызов onAdvance возвращает true. Реализация по умолчанию возвращает
true, если отмена регистрации привела к тому, что число зарегистрированных участников стало равным нулю. Как показано ниже, если фазеры управляют действиями с фиксированным числом итераций, часто удобно переопределить этот метод, чтобы завершение происходило при достижении текущим номером фазы заданного порога. Также доступен метод forceTermination(), который принудительно освобождает ожидающие потоки и позволяет им завершиться.
Иерархия. Фазеры можно объединять в иерархии (то есть создавать в виде деревьев), чтобы уменьшить конкуренцию. Вместо фазеров с большим числом участников, которые в противном случае подвергались бы значительной конкуренции при синхронизации, можно создать группы дочерних фазеров с общим родительским фазером. Это может значительно увеличить пропускную способность, несмотря на увеличение накладных расходов на каждую операцию.
В дереве иерархических фазеров регистрация дочерних фазеров у родительских и отмена такой регистрации выполняются автоматически. Когда число зарегистрированных участников дочернего фазера становится ненулевым (что задается конструктором Phaser(Phaser,int), методом register() или методом bulkRegister(int)), дочерний фазер регистрируется у родительского. Когда число зарегистрированных участников становится равным нулю в результате вызова arriveAndDeregister(), дочерний фазер отменяет регистрацию у родительского.
Мониторинг. Методы синхронизации могут вызываться только зарегистрированными участниками, однако наблюдать за текущим состоянием фазера может любой вызывающий код. В каждый момент времени всего имеется getRegisteredParties() участников, из которых getArrivedParties() прибыли в текущей фазе (getPhase()). Когда прибывают остальные (getUnarrivedParties()) участники, фаза сменяется. Значения, возвращаемые этими методами, могут отражать временные состояния и потому обычно не подходят для управления синхронизацией. Метод toString() возвращает снимок результатов этих запросов о состоянии в форме, удобной для неформального мониторинга.
Эффекты согласованности памяти: действия, предшествующие любой форме метода прибытия, происходят до соответствующей смены фазы и действий onAdvance (если таковые имеются), которые, в свою очередь, происходят до действий после смены фазы.
Примеры использования:
Phaser можно использовать вместо CountDownLatch для управления однократным действием с переменным числом участников. Типичный способ настройки: сначала зарегистрироваться, затем запустить все действия и после этого отменить регистрацию, например:
void runTasks(List<Runnable> tasks) {
Phaser startingGate = new Phaser(1); // "1" to register self
// create and start threads
for (Runnable task : tasks) {
startingGate.register();
new Thread(() -> {
startingGate.arriveAndAwaitAdvance();
task.run();
}).start();
}
// deregister self to allow threads to proceed
startingGate.arriveAndDeregister();
} Чтобы заставить набор потоков многократно выполнять действия в течение заданного числа итераций, можно переопределить onAdvance:
void startTasks(List<Runnable> tasks, int iterations) {
Phaser phaser = new Phaser() {
protected boolean onAdvance(int phase, int registeredParties) {
return phase >= iterations - 1 || registeredParties == 0;
}
};
phaser.register();
for (Runnable task : tasks) {
phaser.register();
new Thread(() -> {
do {
task.run();
phaser.arriveAndAwaitAdvance();
} while (!phaser.isTerminated());
}).start();
}
// allow threads to proceed; don't wait for them
phaser.arriveAndDeregister();
} Если главной задаче позднее потребуется дождаться завершения, она может зарегистрироваться повторно и выполнить аналогичный цикл: // ...
phaser.register();
while (!phaser.isTerminated())
phaser.arriveAndAwaitAdvance(); В связанных конструкциях можно ожидать определенные номера фаз в случаях, когда известно, что номер фазы никогда не перейдет через границу Integer.MAX_VALUE. Например:
void awaitPhase(Phaser phaser, int phase) {
int p = phaser.register(); // assumes caller not already registered
while (p < phase) {
if (phaser.isTerminated())
// ... deal with unexpected termination
else
p = phaser.arriveAndAwaitAdvance();
}
phaser.arriveAndDeregister();
} Чтобы создать набор задач n с использованием дерева фазеров, можно использовать код следующего вида, предполагая, что класс Task имеет конструктор, принимающий Phaser, у которого он регистрируется при создании. После вызова build(new Task[n], 0, n,
new Phaser()) эти задачи можно запустить, например, отправив их в пул:
void build(Task[] tasks, int lo, int hi, Phaser ph) {
if (hi - lo > TASKS_PER_PHASER) {
for (int i = lo; i < hi; i += TASKS_PER_PHASER) {
int j = Math.min(i + TASKS_PER_PHASER, hi);
build(tasks, i, j, new Phaser(ph));
}
} else {
for (int i = lo; i < hi; ++i)
tasks[i] = new Task(ph);
// assumes new Task(ph) performs ph.register()
}
} Оптимальное значение TASKS_PER_PHASER в основном зависит от ожидаемой частоты синхронизации. Для крайне небольших тел задач на фазу (то есть высокой частоты) может подойти значение всего четыре, а для очень больших — до нескольких сотен. Примечания по реализации: эта реализация ограничивает максимальное число участников значением 65535. Попытки зарегистрировать дополнительных участников приводят к IllegalStateException. Однако для работы с произвольно большими группами участников можно и следует создавать иерархические фазеры.
- С версии:
- 1.7
Краткое описание конструкторов
| Конструктор | Описание |
|---|---|
Phaser() |
Создает новый фазер без первоначально зарегистрированных участников, без родительского фазера и с начальным номером фазы 0. |
Phaser |
Создает новый фазер с заданным числом зарегистрированных, но еще не прибывших участников, без родительского фазера и с начальным номером фазы 0. |
Phaser |
Эквивалентен Phaser(parent, 0). |
Phaser |
Создает новый фазер с заданным родительским фазером и числом зарегистрированных, но еще не прибывших участников. |
Краткое описание методов
| Модификатор и тип | Метод | Описание |
|---|---|---|
int |
arrive() |
Прибывает к этому фазеру, не дожидаясь прибытия остальных. |
int |
arriveAndAwaitAdvance() |
Прибывает к этому фазеру и ожидает остальных. |
int |
arriveAndDeregister() |
Прибывает к этому фазеру и отменяет регистрацию, не дожидаясь прибытия остальных. |
int |
awaitAdvance |
Ожидает смены фазы этого фазера относительно заданного значения фазы; немедленно возвращает управление, если текущая фаза не равна заданному значению или этот фазер завершен. |
int |
awaitAdvanceInterruptibly |
Ожидает смены фазы этого фазера относительно заданного значения фазы; выбрасывает InterruptedException при прерывании во время ожидания или немедленно возвращает управление, если текущая фаза не равна заданному значению или этот фазер завершен. |
int |
awaitAdvanceInterruptibly |
Ожидает смены фазы этого фазера относительно заданного значения фазы или истечения заданного времени ожидания; выбрасывает
InterruptedException при прерывании во время ожидания или немедленно возвращает управление, если текущая фаза не равна заданному значению или этот фазер завершен. |
int |
bulkRegister |
Добавляет к этому фазеру заданное число новых, еще не прибывших участников. |
void |
forceTermination() |
Принудительно переводит этот фазер в состояние завершения. |
int |
getArrivedParties() |
Возвращает число зарегистрированных участников, прибывших в текущей фазе этого фазера. |
Phaser |
getParent() |
Возвращает родительский фазер или null, если его нет. |
final int |
getPhase() |
Возвращает текущий номер фазы. |
int |
getRegisteredParties() |
Возвращает число участников, зарегистрированных в этом фазере. |
Phaser |
getRoot() |
Возвращает корневого предка этого фазера, которым является сам фазер, если у него нет родительского фазера. |
int |
getUnarrivedParties() |
Возвращает число зарегистрированных участников, которые еще не прибыли в текущей фазе этого фазера. |
boolean |
isTerminated() |
Возвращает true, если этот фазер завершен. |
protected boolean |
onAdvance |
Переопределяемый метод для выполнения действия перед сменой фазы и управления завершением. |
int |
register() |
Добавляет к этому фазеру нового, еще не прибывшего участника. |
String |
toString() |
Возвращает строку, идентифицирующую этот фазер и его состояние. |
Подробное описание конструкторов
Phaser
public Phaser()
Phaser
public Phaser(int parties)
- Параметры:
-
parties— число участников, необходимое для перехода к следующей фазе - Выбрасывает:
-
IllegalArgumentException— если число участников меньше нуля или превышает максимально поддерживаемое число участников
Phaser
Phaser
public Phaser(Phaser parent, int parties)
- Параметры:
-
parent— родительский фазер -
parties— число участников, необходимое для перехода к следующей фазе - Выбрасывает:
-
IllegalArgumentException— если число участников меньше нуля или превышает максимально поддерживаемое число участников
Подробное описание методов
register
public int register()
onAdvance(int, int), этот метод может дождаться его завершения, прежде чем вернуть управление. Если у этого фазера есть родительский фазер и ранее в нем не было зарегистрированных участников, этот дочерний фазер также регистрируется у родительского. Если этот фазер завершен, попытка регистрации не оказывает никакого эффекта и возвращается отрицательное значение.- Возвращает:
- номер фазы прибытия, к которой относится эта регистрация. Если это значение отрицательное, фазер завершен и регистрация не оказывает никакого эффекта.
- Выбрасывает:
-
IllegalStateException— при попытке зарегистрировать число участников, превышающее максимально поддерживаемое
bulkRegister
public int bulkRegister(int parties)
onAdvance(int, int), этот метод может дождаться его завершения, прежде чем вернуть управление. Если у этого фазера есть родительский фазер, заданное число участников больше нуля, а ранее в этом фазере не было зарегистрированных участников, этот дочерний фазер также регистрируется у родительского. Если этот фазер завершен, попытка регистрации не оказывает никакого эффекта и возвращается отрицательное значение.- Параметры:
-
parties— число дополнительных участников, необходимое для перехода к следующей фазе - Возвращает:
- номер фазы прибытия, к которой относится эта регистрация. Если это значение отрицательное, фазер завершен и регистрация не оказывает никакого эффекта.
- Выбрасывает:
-
IllegalStateException— при попытке зарегистрировать число участников, превышающее максимально поддерживаемое -
IllegalArgumentException— еслиparties < 0
arrive
public int arrive()
Вызов этого метода незарегистрированным участником является ошибкой использования. Однако эта ошибка может привести к
IllegalStateException только при последующей операции с этим фазером, если такая операция вообще будет выполнена.
- Возвращает:
- номер фазы прибытия или отрицательное значение, если фазер завершен
- Выбрасывает:
-
IllegalStateException— если фазер не завершен и число еще не прибывших участников станет отрицательным
arriveAndDeregister
public int arriveAndDeregister()
Вызов этого метода незарегистрированным участником является ошибкой использования. Однако эта ошибка может привести к
IllegalStateException только при последующей операции с этим фазером, если такая операция вообще будет выполнена.
- Возвращает:
- номер фазы прибытия или отрицательное значение, если фазер завершен
- Выбрасывает:
-
IllegalStateException— если фазер не завершен и число зарегистрированных или еще не прибывших участников станет отрицательным
arriveAndAwaitAdvance
public int arriveAndAwaitAdvance()
awaitAdvance(arrive()). Если необходимо ожидание с прерыванием или тайм-аутом, это можно организовать с помощью аналогичной конструкции, использующей одну из других форм метода
awaitAdvance. Если же при прибытии необходимо отменить регистрацию, используйте awaitAdvance(arriveAndDeregister()). Вызов этого метода незарегистрированным участником является ошибкой использования. Однако эта ошибка может привести к
IllegalStateException только при последующей операции с этим фазером, если такая операция вообще будет выполнена.
- Возвращает:
- номер фазы прибытия или (отрицательную) текущую фазу, если фазер завершен
- Выбрасывает:
-
IllegalStateException— если фазер не завершен и число еще не прибывших участников станет отрицательным
awaitAdvance
public int awaitAdvance(int phase)
- Параметры:
-
phase— номер фазы прибытия или отрицательное значение, если фазер завершен; обычно этот аргумент является значением, возвращенным предыдущим вызовомarriveилиarriveAndDeregister. - Возвращает:
- номер следующей фазы прибытия, аргумент, если он отрицателен, или (отрицательную) текущую фазу, если фазер завершен
awaitAdvanceInterruptibly
public int awaitAdvanceInterruptibly(int phase) throws InterruptedException
InterruptedException при прерывании во время ожидания или немедленно возвращает управление, если текущая фаза не равна заданному значению или этот фазер завершен.- Параметры:
-
phase— номер фазы прибытия или отрицательное значение, если фазер завершен; обычно этот аргумент является значением, возвращенным предыдущим вызовомarriveилиarriveAndDeregister. - Возвращает:
- номер следующей фазы прибытия, аргумент, если он отрицателен, или (отрицательную) текущую фазу, если фазер завершен
- Выбрасывает:
-
InterruptedException— если поток прерван во время ожидания
awaitAdvanceInterruptibly
public int awaitAdvanceInterruptibly(int phase, long timeout, TimeUnit unit) throws InterruptedException, TimeoutException
InterruptedException при прерывании во время ожидания или немедленно возвращает управление, если текущая фаза не равна заданному значению или этот фазер завершен.- Параметры:
-
phase— номер фазы прибытия или отрицательное значение, если фазер завершен; обычно этот аргумент является значением, возвращенным предыдущим вызовомarriveилиarriveAndDeregister. -
timeout— сколько ждать до прекращения ожидания, в единицахunit -
unit—TimeUnit, определяющий интерпретацию параметраtimeout - Возвращает:
- номер следующей фазы прибытия, аргумент, если он отрицателен, или (отрицательную) текущую фазу, если фазер завершен
- Выбрасывает:
-
InterruptedException— если поток прерван во время ожидания -
TimeoutException— если время ожидания истекло
forceTermination
public void forceTermination()
getPhase
public final int getPhase()
Integer.MAX_VALUE, после чего нумерация начинается снова с нуля. После завершения номер фазы становится отрицательным; в этом случае номер фазы, действовавший до завершения, можно получить с помощью getPhase() + Integer.MIN_VALUE.- Возвращает:
- номер фазы или отрицательное значение, если фазер завершен
getRegisteredParties
public int getRegisteredParties()
- Возвращает:
- число участников
getArrivedParties
public int getArrivedParties()
- Возвращает:
- число прибывших участников
getUnarrivedParties
public int getUnarrivedParties()
- Возвращает:
- число еще не прибывших участников
getParent
public Phaser getParent()
null, если его нет.- Возвращает:
- родительский фазер или
null, если его нет
getRoot
public Phaser getRoot()
- Возвращает:
- корневой предок этого фазера
isTerminated
public boolean isTerminated()
true, если этот фазер завершен.- Возвращает:
-
true, если этот фазер завершен
onAdvance
protected boolean onAdvance(int phase, int registeredParties)
true, при смене фазы этот фазер перейдет в окончательное состояние завершения, а последующие вызовы isTerminated() вернут true. Любое (непроверяемое) исключение Exception или Error, выброшенное при вызове этого метода, передается участнику, пытающемуся сменить фазу; в этом случае смена фазы не происходит. Аргументы этого метода предоставляют состояние фазера, действующее при текущем переходе. Поведение при вызове методов прибытия, регистрации и ожидания этого фазера изнутри onAdvance не определено, и полагаться на него не следует.
Если этот фазер входит в иерархический набор фазеров, onAdvance вызывается при каждой смене фазы только для корневого фазера.
Для поддержки наиболее распространенных сценариев использования реализация этого метода по умолчанию возвращает true, если число зарегистрированных участников стало равным нулю в результате вызова участником arriveAndDeregister. Это поведение можно отключить и разрешить продолжение работы при последующих регистрациях, переопределив метод так, чтобы он всегда возвращал false:
Phaser phaser = new Phaser() {
protected boolean onAdvance(int phase, int parties) { return false; }
};
- Параметры:
-
phase— текущий номер фазы при входе в этот метод, до смены фазы этого фазера -
registeredParties— текущее число зарегистрированных участников - Возвращает:
-
true, если этот фазер должен завершиться
toString
public String toString()
"phase = ", за которой следует номер фазы, "parties = ", за которым следует число зарегистрированных участников, и
"arrived = ", за которым следует число прибывших участников.
© 1993, 2025, Oracle and/or its affiliates. All rights reserved.
Documentation extracted from Debian's OpenJDK Development Kit package.
Licensed under the GNU General Public License, version 2, with the Classpath Exception.
Various third party code in OpenJDK is licensed under different licenses (see Debian package).
Java and OpenJDK are trademarks or registered trademarks of Oracle and/or its affiliates.
https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/util/concurrent/Phaser.html