Класс Phaser
- java.lang.Object
-
- java.util.concurrent.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() возвращает снимки этих запросов состояния в удобной для неформального мониторинга форме.
Примеры использования:
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(int parties) | Создает новый фазер с заданным количеством зарегистрированных незавершенных участников, без родителя и начальным номером фазы 0. |
Phaser(Phaser parent) | Эквивалентно |
Phaser(Phaser parent,
int parties) | Создает новый фазер с заданным родителем и количеством зарегистрированных незавершенных участников. |
Методы
| Модификатор и тип | Метод | Описание |
|---|---|---|
int | arrive() | Прибывает в этот фазер, не дожидаясь прибытия других. |
int | arriveAndAwaitAdvance() | Прибывает в этот фазер и ожидает других. |
int | arriveAndDeregister() | Прибывает в этот фазер и выходит из него, не дожидаясь прибытия других. |
int | awaitAdvance(int phase) | Ожидает продвижения фазы этого фазера от заданного значения фазы, возвращаясь немедленно, если текущая фаза не равна заданному значению фазы или этот фазер завершен. |
int | awaitAdvanceInterruptibly(int phase) | Ожидает продвижения фазы этого фазера от заданного значения фазы, выбрасывая |
int | awaitAdvanceInterruptibly(int phase,
long timeout,
TimeUnit unit) | Ожидает продвижения фазы этого фазера от заданного значения фазы или истечения заданного таймаута, выбрасывая |
int | bulkRegister(int parties) | Добавляет заданное количество новых участников, которые еще не прибыли, в этот фазер. |
void | forceTermination() | Принудительно переводит этот фазер в состояние завершения. |
int | getArrivedParties() | Возвращает количество зарегистрированных участников, которые прибыли на текущую фазу этого фазера. |
Phaser | getParent() | Возвращает родителя этого фазера или |
int | getPhase() | Возвращает текущий номер фазы. |
int | getRegisteredParties() | Возвращает количество участников, зарегистрированных в этом фазере. |
Phaser | getRoot() | Возвращает корневого предка этого фазера, который совпадает с этим фазером, если у него нет родителя. |
int | getUnarrivedParties() | Возвращает количество зарегистрированных участников, которые еще не прибыли на текущую фазу этого фазера. |
boolean | isTerminated() | Возвращает |
protected boolean | onAdvance(int phase,
int registeredParties) | Переопределяемый метод для выполнения действия при приближении к продвижению фазы и для управления завершением. |
int | register() | Добавляет нового участника, который еще не прибыл, в этот фазер. |
String | toString() | Возвращает строку, идентифицирующую этот фазер, а также его состояние. |
Методы, объявленные в классе java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait Конструкторы
Phaser
public Phaser()
Создает новый фазер без первоначально зарегистрированных участников, без родителя и начальным номером фазы 0. Любой поток, использующий этот фазер, должен сначала зарегистрироваться в нем.
Phaser
public Phaser(int parties)
Создает новый фазер с заданным количеством зарегистрированных участников, которые еще не прибыли, без родителя и начальным номером фазы 0.
- Параметры:
-
parties- количество участников, необходимое для перехода к следующей фазе - Исключения:
-
IllegalArgumentException- если участников меньше нуля или больше максимального поддерживаемого количества участников
Phaser
public Phaser(Phaser parent)
Эквивалентно Phaser(parent, 0).
- Параметры:
-
parent- родительский фазер
Phaser
public Phaser(Phaser parent,
int parties) Создает новый фазер с заданным родителем и количеством зарегистрированных участников, которые еще не прибыли. Когда заданный родитель не null, а заданное количество участников больше нуля, этот дочерний фазер регистрируется у своего родителя.
- Параметры:
-
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. Любое (непроверенное) исключение или ошибка, выброшенная вызовом этого метода, передается стороне, пытающейся продвинуть этот фазер, в этом случае продвижение не происходит.
Аргументы этого метода предоставляют состояние фазера, преобладающее для текущего перехода. Эффекты вызова методов прибытия, регистрации и ожидания на этом фазере изнутри 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, 2020, 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/11/docs/api/java.base/java/util/concurrent/Phaser.html