Spec-Zone.ru › OpenJDK 24

Класс 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() возвращает снимки этих запросов состояния в удобной для неформального мониторинга форме.

Эффекты согласованности памяти: Действия, предшествующие любому виду метода arrive, предшествуют соответствующему переходу фазы и действиям onAdvance (если они присутствуют), которые, в свою очередь, предшествуют действиям, следующим за переходом фазы.

Примеры использования:

Фазер может быть использован вместо 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. Однако вы можете и должны создавать иерархические фазеры для размещения произвольно больших наборов участников.

Since:
1.7

Краткое описание конструкторов

Конструктор Описание
Phaser()
Создаёт новый фазер без первоначально зарегистрированных участников, без родительского фазера и начальным номером фазы 0.
Phaser(int parties)
Создаёт новый фазер с заданным количеством зарегистрированных не пришедших участников, без родительского фазера и начальным номером фазы 0.
Phaser(Phaser parent)
Эквивалентно Phaser(parent, 0).
Phaser(Phaser parent, int parties)
Создаёт новый фазер с заданным родительским фазером и количеством зарегистрированных не пришедших участников.

Краткое описание методов

Модификатор и тип Метод Описание
int arrive()
Приходит в этот фазер без ожидания прихода других.
int arriveAndAwaitAdvance()
Приходит в этот фазер и ожидает других.
int arriveAndDeregister()
Приходит в этот фазер и отписывается от него без ожидания прихода других.
int awaitAdvance(int phase)
Ожидает продвижения фазы этого фазера от заданного значения фазы, возвращаясь немедленно, если текущая фаза не равна заданному значению фазы или этот фазер завершён.
int awaitAdvanceInterruptibly(int phase)
Ожидает продвижения фазы этого фазера от заданного значения фазы, выбрасывая InterruptedException, если прерван во время ожидания, или возвращаясь немедленно, если текущая фаза не равна заданному значению фазы или этот фазер завершён.
int awaitAdvanceInterruptibly(int phase, long timeout, TimeUnit unit)
Ожидает продвижения фазы этого фазера от заданного значения фазы или истечения заданного таймаута, выбрасывая InterruptedException, если прерван во время ожидания, или возвращаясь немедленно, если текущая фаза не равна заданному значению фазы или этот фазер завершён.
int bulkRegister(int parties)
Добавляет заданное количество новых не пришедших участников в этот фазер.
void forceTermination()
Принудительно переводит этот фазер в состояние завершения.
int getArrivedParties()
Возвращает количество зарегистрированных участников, которые пришли в текущей фазе этого фазера.
Phaser getParent()
Возвращает родительского фазера этого фазера, или null, если нет.
final int getPhase()
Возвращает текущий номер фазы.
int getRegisteredParties()
Возвращает количество участников, зарегистрированных в этом фазере.
Phaser getRoot()
Возвращает корневого предка этого фазера, который такой же, как и этот фазер, если у него нет родительского фазера.
int getUnarrivedParties()
Возвращает количество зарегистрированных участников, которые ещё не пришли в текущей фазе этого фазера.
boolean isTerminated()
Возвращает true, если этот фазер завершён.
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 = ", за которым следует количество прибывших участников.
Переопределяет:
toString в классе Object
Возвращает:
строку, идентифицирующую этот фазер, а также его состояние

© 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://download.java.net/java/early_access/jdk24/docs/api/java.base/java/util/concurrent/Phaser.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API