Spec-Zone.ru › OpenJDK 25

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

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

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

Phaser можно использовать вместо CountDownLatch для управления однократным действием с переменным числом участников. Типичный способ настройки: сначала зарегистрироваться, затем запустить все действия и после этого отменить регистрацию, например:

void runTasks(List<Runnable> tasks) {
  Phaser startingGate = new Phaser(1); // "1" to register self
  // create and start threads
  for (Runnable task : tasks) {
    startingGate.register();
    new Thread(() -> {
      startingGate.arriveAndAwaitAdvance();
      task.run();
    }).start();
  }

  // deregister self to allow threads to proceed
  startingGate.arriveAndDeregister();
}

Чтобы заставить набор потоков многократно выполнять действия в течение заданного числа итераций, можно переопределить onAdvance:

void startTasks(List<Runnable> tasks, int iterations) {
  Phaser phaser = new Phaser() {
    protected boolean onAdvance(int phase, int registeredParties) {
      return phase >= iterations - 1 || registeredParties == 0;
    }
  };
  phaser.register();
  for (Runnable task : tasks) {
    phaser.register();
    new Thread(() -> {
      do {
        task.run();
        phaser.arriveAndAwaitAdvance();
      } while (!phaser.isTerminated());
    }).start();
  }
  // allow threads to proceed; don't wait for them
  phaser.arriveAndDeregister();
}
Если главной задаче позднее потребуется дождаться завершения, она может зарегистрироваться повторно и выполнить аналогичный цикл:
  // ...
  phaser.register();
  while (!phaser.isTerminated())
    phaser.arriveAndAwaitAdvance();

В связанных конструкциях можно ожидать определенные номера фаз в случаях, когда известно, что номер фазы никогда не перейдет через границу Integer.MAX_VALUE. Например:

void awaitPhase(Phaser phaser, int phase) {
  int p = phaser.register(); // assumes caller not already registered
  while (p < phase) {
    if (phaser.isTerminated())
      // ... deal with unexpected termination
    else
      p = phaser.arriveAndAwaitAdvance();
  }
  phaser.arriveAndDeregister();
}

Чтобы создать набор задач n с использованием дерева фазеров, можно использовать код следующего вида, предполагая, что класс Task имеет конструктор, принимающий Phaser, у которого он регистрируется при создании. После вызова build(new Task[n], 0, n, new Phaser()) эти задачи можно запустить, например, отправив их в пул:

void build(Task[] tasks, int lo, int hi, Phaser ph) {
  if (hi - lo > TASKS_PER_PHASER) {
    for (int i = lo; i < hi; i += TASKS_PER_PHASER) {
      int j = Math.min(i + TASKS_PER_PHASER, hi);
      build(tasks, i, j, new Phaser(ph));
    }
  } else {
    for (int i = lo; i < hi; ++i)
      tasks[i] = new Task(ph);
      // assumes new Task(ph) performs ph.register()
  }
}
Оптимальное значение TASKS_PER_PHASER в основном зависит от ожидаемой частоты синхронизации. Для крайне небольших тел задач на фазу (то есть высокой частоты) может подойти значение всего четыре, а для очень больших — до нескольких сотен.

Примечания по реализации: эта реализация ограничивает максимальное число участников значением 65535. Попытки зарегистрировать дополнительных участников приводят к IllegalStateException. Однако для работы с произвольно большими группами участников можно и следует создавать иерархические фазеры.

С версии:
1.7

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

Конструктор Описание
Phaser()
Создает новый фазер без первоначально зарегистрированных участников, без родительского фазера и с начальным номером фазы 0.
Phaser(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()
Возвращает строку, идентифицирующую этот фазер и его состояние.

Методы, объявленные в классе 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. Любое (непроверяемое) исключение Exception или Error, выброшенное при вызове этого метода, передается участнику, пытающемуся сменить фазу; в этом случае смена фазы не происходит.

Аргументы этого метода предоставляют состояние фазера, действующее при текущем переходе. Поведение при вызове методов прибытия, регистрации и ожидания этого фазера изнутри onAdvance не определено, и полагаться на него не следует.

Если этот фазер входит в иерархический набор фазеров, onAdvance вызывается при каждой смене фазы только для корневого фазера.

Для поддержки наиболее распространенных сценариев использования реализация этого метода по умолчанию возвращает true, если число зарегистрированных участников стало равным нулю в результате вызова участником arriveAndDeregister. Это поведение можно отключить и разрешить продолжение работы при последующих регистрациях, переопределив метод так, чтобы он всегда возвращал false:

Phaser phaser = new Phaser() {
  protected boolean onAdvance(int phase, int parties) { return false; }
};
Параметры:
phase — текущий номер фазы при входе в этот метод, до смены фазы этого фазера
registeredParties — текущее число зарегистрированных участников
Возвращает:
true, если этот фазер должен завершиться

toString

public String toString()
Возвращает строку, идентифицирующую этот фазер и его состояние. Состояние в квадратных скобках содержит строку "phase = ", за которой следует номер фазы, "parties = ", за которым следует число зарегистрированных участников, и "arrived = ", за которым следует число прибывших участников.
Переопределяет:
toString в классе Object
Возвращает:
строку, идентифицирующую этот фазер и его состояние

Сообщить об ошибке или предложить улучшение
Дополнительную справочную информацию по API и документацию для разработчиков см. в разделе Документация Java SE, содержащем более подробные описания для разработчиков, концептуальные обзоры, определения терминов, обходные решения и примеры работающего кода. Другие версии.
Java является товарным знаком или зарегистрированным товарным знаком Oracle и/или ее дочерних компаний в США и других странах.
Авторские права © 1993, 2025, 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.
https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/util/concurrent/Phaser.html

Spec-Zone.ru

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