Spec-Zone.ru › OpenJDK 17

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

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

Методы, объявленные в классе 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, 2021, 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/17/docs/api/java.base/java/util/concurrent/Phaser.html

Spec-Zone.ru

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