Spec-Zone.ru › OpenJDK 27

Класс Phaser

java.lang.Object
java.util.concurrent.Phaser
public class Phaser extends Object
Многоразовый барьер синхронизации, по функциональности похожий на CyclicBarrier и CountDownLatch, но допускающий более гибкое использование.

Регистрация. В отличие от других барьеров, число зарегистрированных для синхронизации на Phaser участников может меняться со временем. Задачи можно регистрировать в любой момент (с помощью методов register(), bulkRegister(int) или конструкторов, задающих начальное число участников) и при желании отменять их регистрацию при прибытии (с помощью arriveAndDeregister()). Как и в большинстве базовых средств синхронизации, регистрация и отмена регистрации влияют только на внутренние счетчики; они не ведут дополнительного внутреннего учета, поэтому задачи не могут узнать, зарегистрированы ли они. (Однако такой учет можно добавить, создав подкласс этого класса.)

Синхронизация. Как и CyclicBarrier, Phaser можно ожидать многократно. Метод arriveAndAwaitAdvance() действует аналогично CyclicBarrier.await. Каждому поколению Phaser соответствует номер фазы. Нумерация фаз начинается с нуля и увеличивается, когда все участники прибывают к Phaser, после чего при достижении Integer.MAX_VALUE цикл начинается снова с нуля. Номера фаз позволяют независимо управлять действиями при прибытии к Phaser и при ожидании остальных с помощью двух видов методов, которые может вызывать любой зарегистрированный участник:

  • Прибытие. Методы arrive() и arriveAndDeregister() регистрируют прибытие. Эти методы не блокируют выполнение, а возвращают соответствующий номер фазы прибытия, то есть номер фазы Phaser, к которой относится прибытие. Когда прибывает последний участник для данной фазы, выполняется необязательное действие, и фаза увеличивается. Эти действия выполняет участник, вызвавший переход фазы; они определяются переопределением метода onAdvance(int, int), который также управляет завершением. Переопределение этого метода похоже на передачу действия барьера объекту CyclicBarrier, но предоставляет больше гибкости.
  • Ожидание. Метод awaitAdvance(int) принимает аргумент с номером фазы прибытия и возвращает управление, когда Phaser переходит к другой фазе (или уже находится в ней). В отличие от аналогичных конструкций с использованием CyclicBarrier, метод awaitAdvance продолжает ожидание, даже если ожидающий поток прерван. Также доступны версии с обработкой прерываний и тайм-аутом, однако исключения, возникающие при прерываемом ожидании задач или ожидании с тайм-аутом, не изменяют состояние Phaser. При необходимости можно выполнить соответствующие действия по восстановлению в обработчиках этих исключений, часто после вызова forceTermination. Phaser также можно использовать задачам, выполняющимся в ForkJoinPool. Прогресс гарантирован, если уровень параллелизма пула позволяет разместить максимальное число одновременно заблокированных участников.

Завершение. Phaser может перейти в состояние завершения, которое можно проверить с помощью метода isTerminated(). После завершения все методы синхронизации немедленно возвращают управление, не дожидаясь перехода фазы, о чем свидетельствует отрицательное возвращаемое значение. Аналогично, попытки регистрации после завершения не дают эффекта. Завершение происходит, когда вызов onAdvance возвращает true. Реализация по умолчанию возвращает true, если отмена регистрации привела к тому, что число зарегистрированных участников стало равным нулю. Как показано ниже, когда Phaser управляет действиями с фиксированным числом итераций, часто удобно переопределить этот метод, чтобы завершение происходило при достижении текущим номером фазы заданного порога. Для немедленного освобождения ожидающих потоков и возможности их завершения также доступен метод forceTermination().

Иерархическая организация. Phaser можно организовать иерархически (то есть построить в виде дерева), чтобы уменьшить конкуренцию. Вместо Phaser с большим числом участников, который в противном случае подвергался бы значительной конкуренции при синхронизации, можно создать группы подчиненных Phaser с общим родительским Phaser. Это может значительно повысить пропускную способность, несмотря на увеличение накладных расходов на каждую операцию.

В дереве иерархически организованных Phaser регистрация и отмена регистрации дочерних Phaser у родительского выполняются автоматически. Когда число зарегистрированных участников дочернего Phaser становится ненулевым (как задается в конструкторе Phaser(Phaser,int), методах register() или bulkRegister(int)), дочерний Phaser регистрируется у родительского. Когда число зарегистрированных участников становится равным нулю в результате вызова arriveAndDeregister(), дочерний Phaser отменяет регистрацию у родительского.

Мониторинг. Хотя вызывать методы синхронизации могут только зарегистрированные участники, текущее состояние Phaser может отслеживать любой вызывающий код. В любой момент всего имеется 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 с помощью дерева Phaser, можно использовать код следующего вида, предполагая, что у класса 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. Однако для поддержки сколь угодно больших групп участников можно и следует создавать иерархически организованные Phaser.

С версии:
1.7

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

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

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

Модификатор и тип Метод Описание
int arrive()
Отмечает прибытие к этому Phaser, не дожидаясь прибытия остальных.
int arriveAndAwaitAdvance()
Отмечает прибытие к этому Phaser и ожидает остальных.
int arriveAndDeregister()
Отмечает прибытие к этому Phaser и отменяет регистрацию в нем, не дожидаясь прибытия остальных.
int awaitAdvance(int phase)
Ожидает перехода фазы этого Phaser от указанного значения; немедленно возвращает управление, если текущая фаза не равна указанному значению или этот Phaser завершен.
int awaitAdvanceInterruptibly(int phase)
Ожидает перехода фазы этого Phaser от указанного значения; выбрасывает InterruptedException при прерывании во время ожидания или немедленно возвращает управление, если текущая фаза не равна указанному значению либо этот Phaser завершен.
int awaitAdvanceInterruptibly(int phase, long timeout, TimeUnit unit)
Ожидает перехода фазы этого Phaser от указанного значения или истечения заданного тайм-аута; выбрасывает InterruptedException при прерывании во время ожидания или немедленно возвращает управление, если текущая фаза не равна указанному значению либо этот Phaser завершен.
int bulkRegister(int parties)
Добавляет к этому Phaser указанное число новых не прибывших участников.
void forceTermination()
Переводит этот Phaser в состояние завершения.
int getArrivedParties()
Возвращает число зарегистрированных участников, прибывших в текущей фазе этого Phaser.
Phaser getParent()
Возвращает родительский Phaser этого Phaser или null, если его нет.
final int getPhase()
Возвращает текущий номер фазы.
int getRegisteredParties()
Возвращает число участников, зарегистрированных в этом Phaser.
Phaser getRoot()
Возвращает корневой родительский Phaser для этого Phaser, совпадающий с ним самим, если у него нет родителя.
int getUnarrivedParties()
Возвращает число зарегистрированных участников, еще не прибывших в текущей фазе этого Phaser.
boolean isTerminated()
Возвращает true, если этот Phaser завершен.
protected boolean onAdvance(int phase, int registeredParties)
Метод, который можно переопределить для выполнения действия перед переходом фазы и управления завершением.
int register()
Добавляет к этому Phaser нового не прибывшего участника.
String toString()
Возвращает строку, содержащую идентификатор этого Phaser и его состояние.

Методы, объявленные в классе Object

clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait
Модификатор и тип Метод Описание
protected Object clone()
Создает и возвращает копию этого объекта.
boolean equals(Object obj)
Указывает, равен ли другой объект этому объекту.
protected void finalize()
Устарел и будет удален: этот элемент API подлежит удалению в одной из будущих версий.
Финализация устарела и подлежит удалению в одном из будущих выпусков.
final Class<?> getClass()
Возвращает класс времени выполнения этого Object.
int hashCode()
Возвращает хеш-код этого объекта.
final void notify()
Пробуждает один поток, ожидающий на мониторе этого объекта.
final void notifyAll()
Пробуждает все потоки, ожидающие на мониторе этого объекта.
final void wait()
Заставляет текущий поток ожидать пробуждения, обычно в результате уведомления или прерывания.
final void wait(long timeoutMillis)
Заставляет текущий поток ожидать пробуждения, обычно в результате уведомления или прерывания, либо истечения заданного промежутка реального времени.
final void wait(long timeoutMillis, int nanos)
Заставляет текущий поток ожидать пробуждения, обычно в результате уведомления или прерывания, либо истечения заданного промежутка реального времени.

Подробное описание конструкторов

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
Возвращает:
строку, идентифицирующую этот фазер и его состояние

Сообщить об ошибке или предложить улучшение
Дополнительную справочную информацию по API и документацию для разработчиков см. в документации Java SE, содержащей более подробные описания для разработчиков, обзоры концепций, определения терминов, обходные решения и работающие примеры кода. Другие версии.
Java является товарным знаком или зарегистрированным товарным знаком Oracle и/или ее аффилированных лиц в США и других странах.
Авторское право © 1993, 2026, Oracle и/или ее аффилированные лица, 500 Oracle Parkway, Redwood Shores, CA 94065 USA.
Все права защищены. Использование регулируется условиями лицензии и политикой распространения документации.

© 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.

Spec-Zone.ru

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