Класс Phaser
- java.lang.Object
-
- java.util.concurrent.Phaser
public class Phaser extends Object
Переиспользуемый барьер синхронизации, похожий по функциональности на CyclicBarrier и CountDownLatch, но поддерживающий более гибкое использование.
Регистрация. В отличие от других барьеров, количество участников, зарегистрированных для синхронизации на фазе, может меняться со временем. Задачи могут быть зарегистрированы в любое время (с помощью методов register(), bulkRegister(int) или форм конструкторов, устанавливающих начальное количество участников), и, по желанию, могут быть дезактивированы при достижении любой точки (с помощью arriveAndDeregister()). Как и в случае с большинством основных конструкций синхронизации, регистрация и дерегистрация влияют только на внутренние счётчики; они не устанавливают дальнейшее внутреннее ведение записей, поэтому задачи не могут запросить, зарегистрированы ли они. (Однако вы можете ввести такое ведение записей, наследуя этот класс.)
Синхронизация. Как и CyclicBarrier, фаза может быть неоднократно ожидания. Метод 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() возвращает снимки этих запросов состояния в удобной для неформального мониторинга форме.
Примеры использования:
Фаза может быть использована вместо CountDownLatch для управления одноразовым действием, обслуживающим переменное количество участников. Типичный подход состоит в том, что метод, настраивающий это, сначала регистрируется, затем запускает действия, а затем деактивируется, как в:
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();
} Один из способов заставить набор потоков многократно выполнять действия для заданного количества итераций состоит в переопределении onAdvance:
void startTasks(List<Runnable> tasks, final int iterations) {
final Phaser phaser = new Phaser() {
protected boolean onAdvance(int phase, int registeredParties) {
return phase >= iterations || registeredParties == 0;
}
};
phaser.register();
for (final Runnable task : tasks) {
phaser.register();
new Thread() {
public void run() {
do {
task.run();
phaser.arriveAndAwaitAdvance();
} while (!phaser.isTerminated());
}
}.start();
}
phaser.arriveAndDeregister(); // deregister self, don't wait
} Если основной задаче позже нужно будет ожидать завершения, она может перерегистрироваться, а затем выполнить аналогичный цикл: // ...
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. Однако вы можете и должны создавать иерархические фазы для поддержки произвольно больших наборов участников.
- Since:
- 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.