Spec-Zone.ru › OpenJDK 8

Класс Phaser

  • java.lang.Object
    • java.util.concurrent.Phaser

public class Phaser
extends Object

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

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

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

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

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

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

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

Мониторинг. Хотя методы синхронизации могут вызываться только зарегистрированными участниками, текущее состояние фазы может быть отслежено любым вызывающим лицом. В любой момент времени есть getRegisteredParties() участников в целом, из которых getArrivedParties() прибыли на текущую фазу (getPhase()). Когда оставшиеся (getUnarrivedParties()) участники придут, фаза перейдёт на следующую ступень. Значения, возвращаемые этими методами, могут отражать временные состояния, и поэтому в общем случае не подходят для управления синхронизацией. Метод toString() возвращает снимки этих запросов состояния в удобной для неформального мониторинга форме.

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

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

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

   // allow threads to start and deregister self
   phaser.arriveAndDeregister();
 }

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

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

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

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

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

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

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

Since:
1.7

Конструкторы

Конструктор и описание
Phaser()

Создаёт новую фазу без первоначально зарегистрированных участников, без родителя и начальным номером фазы 0.

Phaser(int parties)

Создаёт новую фазу с заданным количеством зарегистрированных незавершенных участников, без родителя и начальным номером фазы 0.

Phaser(Phaser parent)

Эквивалентно Phaser(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 если родителя нет.

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, 2020, Oracle and/or its affiliates. All rights reserved.
Documentation extracted from Debian's OpenJDK Development Kit package.
Licensed under the GNU General Public License, version 2, with the Classpath Exception.
Various third party code in OpenJDK is licensed under different licenses (see Debian package).
Java and OpenJDK are trademarks or registered trademarks of Oracle and/or its affiliates.

Spec-Zone.ru

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