Класс CountedCompleter<T>
- Параметры типа:
T- тип результата завершения
- Все реализованные интерфейсы:
-
Serializable,Future<T>
public abstract class CountedCompleter<T> extends ForkJoinTask<T>
ForkJoinTask с действием завершения, выполняемым при срабатывании и отсутствии оставшихся ожидающих действий. CountedCompleters, как правило, более устойчивы к остановкам и блокировкам подзадач, чем другие формы ForkJoinTasks, но программирование с ними менее интуитивно. Использование CountedCompleter аналогично использованию других компонентов на основе завершения (таких как CompletionHandler), за исключением того, что для запуска действия завершения onCompletion(CountedCompleter) может потребоваться несколько ожидающих завершений, а не только одно. Если не указано иное, счётчик ожидающих задач равен нулю, но может быть (атомарно) изменён с помощью методов setPendingCount(int), addToPendingCount(int) и compareAndSetPendingCount(int, int). При вызове tryComplete(), если счётчик ожидающих задач не равен нулю, он уменьшается; в противном случае выполняется действие завершения, и если у этой задачи есть своя задача-завершитель, процесс продолжается с её завершителем. Как и в случае с аналогичными компонентами синхронизации, такими как Phaser и Semaphore, эти методы влияют только на внутренние счётчики; они не устанавливают дополнительную внутреннюю учётную запись. В частности, идентификаторы ожидающих задач не сохраняются. Как показано ниже, вы можете создать подклассы, которые при необходимости записывают некоторые или все ожидающие задачи или их результаты. Как показано ниже, также предоставляются вспомогательные методы, поддерживающие настройку проходов завершения. Однако, поскольку CountedCompleters предоставляют только базовые механизмы синхронизации, может быть полезно создать дополнительные абстрактные подклассы, которые поддерживают связи, поля и дополнительные вспомогательные методы, подходящие для набора связанных применений. Конкретный класс CountedCompleter должен определить метод compute(), который в большинстве случаев (как показано ниже) должен вызвать tryComplete() перед возвратом. Класс также может по желанию переопределить метод onCompletion(CountedCompleter) для выполнения действия при нормальном завершении и метод onExceptionalCompletion(Throwable, CountedCompleter) для выполнения действия при возникновении исключения.
Задания CountedCompleters чаще всего не возвращают результатов, в этом случае они обычно объявляются как CountedCompleter<Void> и всегда возвращают null в качестве значения результата. В других случаях вы должны переопределить метод getRawResult() для предоставления результата от join(), invoke() и связанных методов. В общем случае этот метод должен возвращать значение поля (или функции от одного или нескольких полей) объекта CountedCompleter, хранящего результат при завершении. Метод setRawResult(T) по умолчанию не играет роли в CountedCompleters. Возможно, но редко применимо, переопределить этот метод для сохранения других объектов или полей, содержащих данные результата.
CountedCompleter, у которого нет завершителя (т.е. для которого getCompleter() возвращает null), может быть использован как обычная задача ForkJoinTask с этой дополнительной функциональностью. Однако любой завершитель, у которого, в свою очередь, есть другой завершитель, служит только внутренним помощником для других вычислений, поэтому его собственный статус задачи (как сообщается в методах, таких как ForkJoinTask.isDone()) произволен; этот статус изменяется только при явных вызовах complete(T), ForkJoinTask.cancel(boolean), ForkJoinTask.completeExceptionally(Throwable) или при возникновении исключения в методе compute. При любом исключительном завершении исключение может быть передано завершителю задачи (и его завершителю, и так далее), если он существует и не завершился иначе. Аналогично, отмена внутренней задачи CountedCompleter имеет только локальный эффект на эту задачу, поэтому часто бесполезна.
Примеры использования.
Параллельное рекурсивное разбиение. CountedCompleters могут быть организованы в деревья, аналогичные тем, что часто используются с RecursiveAction, хотя конструкции, используемые для их настройки, обычно различаются. Здесь завершитель каждой задачи является её родителем в дереве вычислений. Несмотря на то, что они требуют немного больше учёта, CountedCompleters могут быть лучшим выбором при применении, возможно, длительной операции (которую нельзя далее разделить) к каждому элементу массива или коллекции; особенно когда операция занимает значительно разное время для завершения для некоторых элементов, либо из-за внутренних различий (например, ввода-вывода), либо из-за побочных эффектов, таких как сборка мусора. Поскольку CountedCompleters предоставляют собственные продолжения, другие задачи не должны блокироваться в ожидании их выполнения.
Например, вот начальная версия вспомогательного метода, использующего рекурсивное разбиение пополам для деления работы на отдельные части (задачи листьев). Даже когда работа разбивается на отдельные вызовы, древовидные методы обычно предпочтительнее прямого разбиения задач-листьев, потому что они уменьшают межпотоковую коммуникацию и улучшают балансировку нагрузки. В рекурсивном случае вторая из каждой пары подзадач, завершившая работу, инициирует завершение их родителя (поскольку комбинирования результатов не выполняется, реализация по умолчанию без действий метода onCompletion не переопределяется). Вспомогательный метод настраивает задачу-корень и вызывает её (здесь неявно используется ForkJoinPool.commonPool()). Простой и надёжный (но не оптимальный) способ — всегда устанавливать счётчик ожидающих задач в количество дочерних задач и вызывать
tryComplete() непосредственно перед возвратом.
public static <E> void forEach(E[] array, Consumer<E> action) {
class Task extends CountedCompleter<Void> {
final int lo, hi;
Task(Task parent, int lo, int hi) {
super(parent); this.lo = lo; this.hi = hi;
}
public void compute() {
if (hi - lo >= 2) {
int mid = (lo + hi) >>> 1;
// must set pending count before fork
setPendingCount(2);
new Task(this, mid, hi).fork(); // right child
new Task(this, lo, mid).fork(); // left child
}
else if (hi > lo)
action.accept(array[lo]);
tryComplete();
}
}
new Task(null, 0, array.length).invoke();
} Этот дизайн можно улучшить, заметив, что в рекурсивном случае задача ничего не должна делать после разбиения своей правой задачи, поэтому может напрямую вызвать свою левую задачу перед возвратом. (Это аналог удаления рекурсии хвостового вызова.) Также, когда последним действием в задаче является разбиение или вызов подзадачи («хвостовой вызов»), вызов
tryComplete() можно оптимизировать, но при этом счётчик ожидающих задач может выглядеть «неправильным на единицу».
public void compute() {
if (hi - lo >= 2) {
int mid = (lo + hi) >>> 1;
setPendingCount(1); // looks off by one, but correct!
new Task(this, mid, hi).fork(); // right child
new Task(this, lo, mid).compute(); // direct invoke
} else {
if (hi > lo)
action.accept(array[lo]);
tryComplete();
}
} В качестве дальнейшей оптимизации обратите внимание, что левая задача даже не обязательно должна существовать. Вместо создания новой можно продолжить использование исходной задачи и добавить счётчик ожидающих задач для каждого разбиения. Кроме того, поскольку ни одна задача в этом дереве не реализует метод onCompletion(CountedCompleter), tryComplete можно заменить на propagateCompletion().
public void compute() {
int n = hi - lo;
for (; n >= 2; n /= 2) {
addToPendingCount(1);
new Task(this, lo + n/2, lo + n).fork();
}
if (n > 0)
action.accept(array[lo]);
propagateCompletion();
} Если счётчики ожидающих задач можно предварительно вычислить, они могут быть установлены в конструкторе:
public static <E> void forEach(E[] array, Consumer<E> action) {
class Task extends CountedCompleter<Void> {
final int lo, hi;
Task(Task parent, int lo, int hi) {
super(parent, 31 - Integer.numberOfLeadingZeros(hi - lo));
this.lo = lo; this.hi = hi;
}
public void compute() {
for (int n = hi - lo; n >= 2; n /= 2)
new Task(this, lo + n/2, lo + n).fork();
action.accept(array[lo]);
propagateCompletion();
}
}
if (array.length > 0)
new Task(null, 0, array.length).invoke();
} Дополнительные оптимизации таких классов могут включать специализацию классов для этапов листьев, деление на, скажем, четыре, а не на два на итерацию, и использование адаптивного порога вместо всегда разбиения до единичных элементов. Поиск. Дерево CountedCompleters может искать значение или свойство в разных частях структуры данных и сообщать о результате в AtomicReference как только оно будет найдено. Остальные могут опросить результат, чтобы избежать ненужной работы. (Вы также можете отменить другие задачи, но обычно проще и эффективнее просто позволить им заметить, что результат установлен, и в этом случае пропустить дальнейшую обработку.) Ещё раз иллюстрируем с массивом, используя полное разделение (снова, на практике задачи-листья почти всегда будут обрабатывать более одного элемента):
class Searcher<E> extends CountedCompleter<E> {
final E[] array; final AtomicReference<E> result; final int lo, hi;
Searcher(CountedCompleter<?> p, E[] array, AtomicReference<E> result, int lo, int hi) {
super(p);
this.array = array; this.result = result; this.lo = lo; this.hi = hi;
}
public E getRawResult() { return result.get(); }
public void compute() { // similar to ForEach version 3
int l = lo, h = hi;
while (result.get() == null && h >= l) {
if (h - l >= 2) {
int mid = (l + h) >>> 1;
addToPendingCount(1);
new Searcher(this, array, result, mid, h).fork();
h = mid;
}
else {
E x = array[l];
if (matches(x) && result.compareAndSet(null, x))
quietlyCompleteRoot(); // root task is now joinable
break;
}
}
tryComplete(); // normally complete whether or not found
}
boolean matches(E e) { ... } // return true if found
public static <E> E search(E[] array) {
return new Searcher<E>(null, array, new AtomicReference<E>(), 0, array.length).invoke();
}
} В этом примере, а также в других, в которых задачи не имеют других эффектов, кроме как compareAndSet общего результата, заключительный безусловный вызов tryComplete можно сделать условным (if (result.get() == null) tryComplete();), так как для управления завершениями после завершения задачи-корня больше нет необходимости в дополнительной учётной записи. Запись подзадач. Задачи CountedCompleter, которые объединяют результаты нескольких подзадач, обычно должны получить доступ к этим результатам в методе onCompletion(CountedCompleter). Как показано в следующем классе (выполняющем упрощённую форму map-reduce, где отображения и сводки являются всех типа E), один из способов сделать это в дизайнах divide and conquer — это заставить каждую подзадачу записывать своего брата, чтобы к нему можно было получить доступ в методе onCompletion. Этот метод применим к сводкам, в которых порядок объединения левых и правых результатов не важен; упорядоченные сводки требуют явных левых/правых обозначений. Также могут применяться варианты других оптимизаций, показанных в примерах выше.
class MyMapper<E> { E apply(E v) { ... } }
class MyReducer<E> { E apply(E x, E y) { ... } }
class MapReducer<E> extends CountedCompleter<E> {
final E[] array; final MyMapper<E> mapper;
final MyReducer<E> reducer; final int lo, hi;
MapReducer<E> sibling;
E result;
MapReducer(CountedCompleter<?> p, E[] array, MyMapper<E> mapper,
MyReducer<E> reducer, int lo, int hi) {
super(p);
this.array = array; this.mapper = mapper;
this.reducer = reducer; this.lo = lo; this.hi = hi;
}
public void compute() {
if (hi - lo >= 2) {
int mid = (lo + hi) >>> 1;
MapReducer<E> left = new MapReducer(this, array, mapper, reducer, lo, mid);
MapReducer<E> right = new MapReducer(this, array, mapper, reducer, mid, hi);
left.sibling = right;
right.sibling = left;
setPendingCount(1); // only right is pending
right.fork();
left.compute(); // directly execute left
}
else {
if (hi > lo)
result = mapper.apply(array[lo]);
tryComplete();
}
}
public void onCompletion(CountedCompleter<?> caller) {
if (caller != this) {
MapReducer<E> child = (MapReducer<E>)caller;
MapReducer<E> sib = child.sibling;
if (sib == null || sib.result == null)
result = child.result;
else
result = reducer.apply(child.result, sib.result);
}
}
public E getRawResult() { return result; }
public static <E> E mapReduce(E[] array, MyMapper<E> mapper, MyReducer<E> reducer) {
return new MapReducer<E>(null, array, mapper, reducer,
0, array.length).invoke();
}
} Здесь метод onCompletion принимает форму, общую для многих дизайнов завершений, которые объединяют результаты. Этот метод в стиле обратного вызова срабатывает один раз на задачу в любом из двух различных контекстов, в которых счётчик ожидающих задач равен или становится равным нулю: (1) сама задача, если её счётчик ожидающих задач равен нулю при вызове
tryComplete, или (2) любой из её подзадач, когда они завершаются и уменьшают счётчик ожидающих задач до нуля. Аргумент caller различает случаи. Чаще всего, когда вызывающая сторона является this, никаких действий не требуется. В противном случае вызывающая сторона может быть использована (обычно через приведение типа) для предоставления значения (и/или ссылок на другие значения) для объединения. При условии правильного использования счётчиков ожидающих задач действия внутри onCompletion выполняются (один раз) при завершении задачи и её подзадач. Дополнительная синхронизация внутри этого метода не требуется для обеспечения потокобезопасности доступа к полям этой задачи или других завершенных задач. Проходы завершения. Если использование onCompletion для обработки завершений неприменимо или неудобно, вы можете использовать методы firstComplete() и nextComplete() для создания пользовательских проходов. Например, для определения MapReducer, который разделяет только правые задачи в форме третьего примера ForEach, завершения должны кооперативно сводиться вдоль неиспользованных связей подзадач, что можно сделать следующим образом:
class MapReducer<E> extends CountedCompleter<E> { // version 2
final E[] array; final MyMapper<E> mapper;
final MyReducer<E> reducer; final int lo, hi;
MapReducer<E> forks, next; // record subtask forks in list
E result;
MapReducer(CountedCompleter<?> p, E[] array, MyMapper<E> mapper,
MyReducer<E> reducer, int lo, int hi, MapReducer<E> next) {
super(p);
this.array = array; this.mapper = mapper;
this.reducer = reducer; this.lo = lo; this.hi = hi;
this.next = next;
}
public void compute() {
int l = lo, h = hi;
while (h - l >= 2) {
int mid = (l + h) >>> 1;
addToPendingCount(1);
(forks = new MapReducer(this, array, mapper, reducer, mid, h, forks)).fork();
h = mid;
}
if (h > l)
result = mapper.apply(array[l]);
// process completions by reducing along and advancing subtask links
for (CountedCompleter<?> c = firstComplete(); c != null; c = c.nextComplete()) {
for (MapReducer t = (MapReducer)c, s = t.forks; s != null; s = t.forks = s.next)
t.result = reducer.apply(t.result, s.result);
}
}
public E getRawResult() { return result; }
public static <E> E mapReduce(E[] array, MyMapper<E> mapper, MyReducer<E> reducer) {
return new MapReducer<E>(null, array, mapper, reducer,
0, array.length, null).invoke();
}
} Триггеры. Некоторые CountedCompleters сами никогда не разделяются, а вместо этого служат элементами трубопровода в других конструкциях; включая те, в которых завершение одной или нескольких асинхронных задач запускает другую асинхронную задачу. Например:
class HeaderBuilder extends CountedCompleter<...> { ... }
class BodyBuilder extends CountedCompleter<...> { ... }
class PacketSender extends CountedCompleter<...> {
PacketSender(...) { super(null, 1); ... } // trigger on second completion
public void compute() { } // never called
public void onCompletion(CountedCompleter<?> caller) { sendPacket(); }
}
// sample use:
PacketSender p = new PacketSender();
new HeaderBuilder(p, ...).fork();
new BodyBuilder(p, ...).fork();
- Since:
- 1.8
- See Also:
Краткое описание вложенных классов
Вложенные классы/интерфейсы, объявленные в интерфейсе java.util.concurrent.Future
Future.State
Краткое описание конструкторов
| Модификатор | Конструктор | Описание |
|---|---|---|
protected |
Создаёт новый CountedCompleter без комплетора и начальным значением ожидаемого подсчёта равным нулю. |
|
protected |
Создаёт новый CountedCompleter с заданным комплетором и начальным значением ожидаемого подсчёта равным нулю. |
|
protected |
Создаёт новый CountedCompleter с заданным комплетором и начальным значением ожидаемого подсчёта. |
Краткое описание методов
| Модификатор и тип | Метод | Описание |
|---|---|---|
final void |
addToPendingCount |
Добавляет (атомарно) заданное значение к ожидаемому подсчёту. |
final boolean |
compareAndSetPendingCount |
Устанавливает (атомарно) ожидаемый подсчёт в заданное значение, только если он в настоящее время имеет заданное ожидаемое значение. |
void |
complete |
Независимо от ожидаемого подсчёта, вызывает onCompletion(CountedCompleter), помечает эту задачу как завершенную и дополнительно запускает tryComplete() для комплетора этой задачи, если он существует. |
abstract void |
compute() |
Основное вычисление, выполняемое этой задачей. |
final int |
decrementPendingCountUnlessZero() |
Если ожидаемый подсчёт отличен от нуля, (атомарно) уменьшает его. |
protected final boolean |
exec() |
Реализует соглашения об выполнении для CountedCompleters. |
final CountedCompleter |
firstComplete() |
Если ожидаемый подсчёт этой задачи равен нулю, возвращает эту задачу; в противном случае уменьшает ожидаемый подсчёт и возвращает null. |
final CountedCompleter |
getCompleter() |
Возвращает комплетор, установленный в конструкторе этой задачи, или null, если он отсутствует. |
final int |
getPendingCount() |
Возвращает текущий ожидаемый подсчёт. |
T |
getRawResult() |
Возвращает результат вычисления. |
final CountedCompleter |
getRoot() |
Возвращает корень текущего вычисления; т.е., эту задачу, если у неё нет комплетора, иначе корень комплетора. |
final void |
helpComplete |
Если эта задача не завершена, пытается обработать не более заданного количества других необработанных задач, для которых эта задача находится на пути завершения, если такие существуют. |
final CountedCompleter |
nextComplete() |
Если у этой задачи нет комплетора, вызывает ForkJoinTask.quietlyComplete() и возвращает null. |
void |
onCompletion |
Выполняет действие, когда метод tryComplete() вызывается, и ожидаемый подсчёт равен нулю, или когда вызывается безусловный метод complete(T). |
boolean |
onExceptionalCompletion |
Выполняет действие, когда вызывается метод ForkJoinTask.completeExceptionally(Throwable) или метод compute() выбрасывает исключение, и эта задача ещё не завершена обычным способом. |
final void |
propagateCompletion() |
Эквивалентно tryComplete(), но не вызывает onCompletion(CountedCompleter) по пути завершения: если ожидаемый подсчёт отличен от нуля, уменьшает подсчёт; в противном случае аналогично пытается завершить комплетор этой задачи, если он существует, иначе помечает эту задачу как завершенную. |
final void |
quietlyCompleteRoot() |
Эквивалентно getRoot().quietlyComplete(). |
final void |
setPendingCount |
Устанавливает ожидаемый подсчёт в заданное значение. |
protected void |
setRawResult |
Метод, который результирующие CountedCompleters могут использовать, чтобы помочь сохранить данные результатов. |
final void |
tryComplete() |
Если ожидаемый подсчёт отличен от нуля, уменьшает его; иначе вызывает onCompletion(CountedCompleter), а затем аналогично пытается завершить комплетор этой задачи, если он существует, иначе помечает эту задачу как завершенную. |
Методы, объявленные в классе java.util.concurrent.ForkJoinTask
adapt, adapt, adapt, adaptInterruptible, adaptInterruptible, adaptInterruptible, cancel, compareAndSetForkJoinTaskTag, completeExceptionally, exceptionNow, fork, get, get, getException, getForkJoinTaskTag, getPool, getQueuedTaskCount, getSurplusQueuedTaskCount, helpQuiesce, inForkJoinPool, invoke, invokeAll, invokeAll, invokeAll, isCancelled, isCompletedAbnormally, isCompletedNormally, isDone, join, peekNextLocalTask, pollNextLocalTask, pollSubmission, pollTask, quietlyComplete, quietlyInvoke, quietlyJoin, quietlyJoin, quietlyJoinUninterruptibly, reinitialize, resultNow, setForkJoinTaskTag, state, tryUnfork
Подробное описание конструкторов
CountedCompleter
protected CountedCompleter(CountedCompleter<?> completer, int initialPendingCount)
- Параметры:
-
completer- completer данной задачи илиnull, если нет -
initialPendingCount- начальное значение счётчика ожиданий
CountedCompleter
protected CountedCompleter(CountedCompleter<?> completer)
- Параметры:
-
completer- completer данной задачи илиnull, если нет
CountedCompleter
protected CountedCompleter()
Подробное описание методов
compute
public abstract void compute()
onCompletion
public void onCompletion(CountedCompleter<?> caller)
tryComplete() вызывается и счётчик ожиданий равен нулю, или когда вызывается безусловный метод complete(T). По умолчанию этот метод ничего не делает. Можно различать случаи, проверяя идентичность переданного аргумента вызывающей задачи. Если он не равен
this, то это обычно подзадача, которая может содержать результаты (и/или ссылки на другие результаты) для объединения.- Параметры:
-
caller- задача, вызывающая этот метод (которая может быть самой этой задачей)
onExceptionalCompletion
public boolean onExceptionalCompletion(Throwable ex, CountedCompleter<?> caller)
ForkJoinTask.completeExceptionally(Throwable) или метод compute() выбрасывает исключение, и эта задача ещё не завершилась нормально. При входе в этот метод, задача ForkJoinTask.isCompletedAbnormally(). Возвращаемое значение этого метода управляет дальнейшей передачей: если true и у этой задачи есть completer, который ещё не завершен, то этот completer также завершается с исключением, таким же, как и у этого completer. По умолчанию этот метод ничего не делает, кроме как возвращает true.- Параметры:
-
ex- исключение -
caller- задача, вызывающая этот метод (которая может быть самой этой задачей) - Возвращает:
-
true, если это исключение должно быть передано completer этой задачи, если он существует
getCompleter
public final CountedCompleter<?> getCompleter()
null, если его нет.- Возвращает:
- completer
getPendingCount
public final int getPendingCount()
- Возвращает:
- текущее значение счётчика ожиданий
setPendingCount
public final void setPendingCount(int count)
- Параметры:
-
count- значение счётчика
addToPendingCount
public final void addToPendingCount(int delta)
- Параметры:
-
delta- значение для добавления
compareAndSetPendingCount
public final boolean compareAndSetPendingCount(int expected, int count)
- Параметры:
-
expected- ожидаемое значение -
count- новое значение - Возвращает:
-
true, если операция выполнена успешно
decrementPendingCountUnlessZero
public final int decrementPendingCountUnlessZero()
- Возвращает:
- начальное (неуменьшенное) значение счётчика ожиданий на момент входа в этот метод
getRoot
public final CountedCompleter<?> getRoot()
- Возвращает:
- корень текущего вычисления
tryComplete
public final void tryComplete()
onCompletion(CountedCompleter), а затем аналогично пытается завершить completer этой задачи, если он существует, иначе помечает эту задачу как завершённую.propagateCompletion
public final void propagateCompletion()
tryComplete(), но не вызывает onCompletion(CountedCompleter) вдоль пути завершения: Если счётчик ожиданий не равен нулю, уменьшает его на 1; иначе аналогично пытается завершить completer этой задачи, если он существует, иначе помечает эту задачу как завершённую. Этот метод может быть полезен в случаях, когда onCompletion не должен или не нуждается в вызове для каждого completer в вычислении.complete
public void complete(T rawResult)
onCompletion(CountedCompleter), помечает эту задачу как завершенную и далее запускает tryComplete() на completer этой задачи, если он существует. Переданное значение rawResult используется в качестве аргумента для setRawResult(T) до вызова onCompletion(CountedCompleter) или пометки этой задачи как завершенной; его значение имеет смысл только для классов, переопределяющих setRawResult. Этот метод не изменяет значение счётчика ожиданий. Этот метод может быть полезен, когда требуется принудительное завершение, как только получен результат любой (а не всех) из нескольких подзадач. Однако в общем (и рекомендуемом) случае, когда
setRawResult не переопределен, этот эффект можно получить проще, используя quietlyCompleteRoot().
- Overrides:
-
completeв классеForkJoinTask<T> - Параметры:
-
rawResult- необработанный результат
firstComplete
public final CountedCompleter<?> firstComplete()
null. Этот метод предназначен для использования с nextComplete() в циклах обхода завершения.- Возвращает:
- эту задачу, если счётчик ожиданий был равен нулю, иначе
null
nextComplete
public final CountedCompleter<?> nextComplete()
ForkJoinTask.quietlyComplete() и возвращает null. Или, если счётчик ожиданий completer не равен нулю, уменьшает этот счётчик и возвращает null. В противном случае возвращает completer. Этот метод может быть использован как часть цикла обхода завершения для однородных иерархий задач:
for (CountedCompleter<?> c = firstComplete();
c != null;
c = c.nextComplete()) {
// ... process c ...
}
- Возвращает:
- completer, или
null, если его нет
quietlyCompleteRoot
public final void quietlyCompleteRoot()
getRoot().quietlyComplete().helpComplete
public final void helpComplete(int maxTasks)
- Параметры:
-
maxTasks- максимальное количество задач для обработки. Если меньше или равно нулю, то никакие задачи не обрабатываются.
exec
protected final boolean exec()
- Определено в:
-
execв классеForkJoinTask<T> - Возвращает:
-
true, если известно, что эта задача завершилась нормально
getRawResult
public T getRawResult()
null, что подходит для Void действий, но в других случаях следует переопределять, практически всегда возвращая поле или функцию поля, содержащего результат после завершения.- Определено в:
-
getRawResultв классеForkJoinTask<T> - Возвращает:
- результат вычисления
setRawResult
protected void setRawResult(T t)
- Specified by:
-
setRawResultв классеForkJoinTask<T> - Параметры:
-
t- значение
© 1993, 2025, Oracle and/or its affiliates. All rights reserved.
Documentation extracted from Debian's OpenJDK Development Kit package.
Licensed under the GNU General Public License, version 2, with the Classpath Exception.
Various third party code in OpenJDK is licensed under different licenses (see Debian package).
Java and OpenJDK are trademarks or registered trademarks of Oracle and/or its affiliates.
https://download.java.net/java/early_access/jdk24/docs/api/java.base/java/util/concurrent/CountedCompleter.html