Interface StructuredTaskScope.Joiner<T, R, R_X extends Throwable>
- Type Parameters:
T- the result type of subtasks forkedPREVIEW in the scopeR- the type of the result returned by thejoin()PREVIEW methodR_X- the type of the exception thrown by thejoin()PREVIEW method
Joiner is a preview API of the Java platform.
StructuredTaskScopePREVIEW to produce the outcome for the
scope's join()PREVIEW method.
A StructuredTaskScope is opened with a Joiner that handles
subtasks as they are forkedPREVIEW in
the scope and again when they complete execution. The Joiner handles
subtasks that complete successfully with a result of type T, or fail with
any exception or error. The Joiner implements a policy that may
cancel the scope when some condition
is reached (for example, a subtask fails). When all subtasks complete execution, or
the scope is cancelled, the Joiner produces the outcome for the join()PREVIEW method. The outcome is a result of type R or an exception
of type R_X.
Joiner defines static methods to create Joiner objects for
common cases:
-
allSuccessfulOrThrow()andallSuccessfulOrThrow(Function)create aJoinerthat produces a list of all results forjoin()to return when all subtasks complete successfully. TheJoinercancels the scope and causesjoin()to throwExecutionException, or an exception returned by an exception supplying function, if any subtask fails. -
anySuccessfulOrThrow()andanySuccessfulOrThrow(Function)create aJoinerthat produces the result of any successful subtask forjoin()to return. TheJoinercausesjoin()to throwExecutionException, or an exception returned by an exception supplying function, if all subtasks fail. -
awaitAllSuccessfulOrThrow()andawaitAllSuccessfulOrThrow(Function)create aJoinerthat waits for all subtasks to complete successfully. TheJoinerdoes not produce a non-nullresult forjoin()to return. TheJoinercancels the scope and causesjoin()to throwExecutionException, or an exception returned by an exception supplying function, if any subtask fails.
In addition to the methods to create Joiner objects for common cases,
the allUntil(Predicate) method can be used to create a
Joiner that implements a cancellation policy. The Joiner
is created with a predicate that is evaluated on completed
subtasks. The Joiner cancels
the scope if the predicate evaluates to true. When using this Joiner,
the outcome of the join() method is the list of all subtasks forked in the
scope.
More advanced policies can be developed by implementing the Joiner
interface. The onFork(Subtask) method is invoked when subtasks are forked.
The onComplete(Subtask) method is invoked when subtasks complete with a
result or exception. These methods return a boolean to indicate whether the
scope should be cancelled. These methods can be used to collect subtasks, results,
or exceptions, and control when to cancel the scope. The result() method
must be implemented to produce the outcome (result or exception) for the
join() method. The timeout() method must be implemented to produce the
outcome for the timeoutPREVIEW case.
Unless otherwise specified, passing a null argument to a method
in this class will cause a NullPointerException to be thrown.
- API Note:
- It is very important that a new
Joinerobject is created for eachStructuredTaskScope.Joinerobjects should never be shared with different scopes or re-used after a scope is closed. - Implementation Requirements:
- Implementations of this interface must be thread-safe. The
onComplete(Subtask)method may be invoked concurrently as multiple subtasks can complete at the same time. Additionally, theonComplete(Subtask)method may be called concurrently with the scope owner thread invoking theonFork(Subtask),result(), ortimeout()methods.A
Joinershould clearly document how it handles timeoutsPREVIEW. In many cases, a timeout will cause thejoin()method to throw an exception withCancelledByTimeoutExceptionPREVIEW as the cause. SomeJoinerimplementation may be capable of returning a result for the timeout case.Designing a
Joinershould take into account the code at the use-site where the results from thejoin()PREVIEW method are processed. It should be clear what theJoinerdoes vs. the application code at the use-site. In general, theJoinerimplementation is not the place for "business logic". AJoinershould be designed to be as general purpose as possible. - Since:
- 25
- See Also:
-
Method Summary
Modifier and TypeMethodDescriptionstatic <T> StructuredTaskScope.JoinerPREVIEW<T, List<T>, ExecutionException> Returns a new Joiner that produces a list of all results when all subtasks complete successfully.static <T, R_X extends Throwable>
StructuredTaskScope.JoinerPREVIEW<T, List<T>, R_X> allSuccessfulOrThrow(Function<Throwable, R_X> esf) Returns a new Joiner that produces a list of all results when all subtasks complete successfully.static <T> StructuredTaskScope.JoinerPREVIEW<T, List<StructuredTaskScope.SubtaskPREVIEW<T>>, RuntimeException> allUntil(Predicate<? super StructuredTaskScope.SubtaskPREVIEW<T>> isDone) Returns a new Joiner that produces a list of all subtasks when all subtasks complete or evaluating a predicate on a completed subtask causes the scope to be cancelled.static <T> StructuredTaskScope.JoinerPREVIEW<T, T, ExecutionException> Returns a new Joiner that produces the result of any successful subtask.static <T, R_X extends Throwable>
StructuredTaskScope.JoinerPREVIEW<T, T, R_X> anySuccessfulOrThrow(Function<Throwable, R_X> esf) Returns a new Joiner that produces the result of any successful subtask.static <T> StructuredTaskScope.JoinerPREVIEW<T, Void, ExecutionException> static <T, R_X extends Throwable>
StructuredTaskScope.JoinerPREVIEW<T, Void, R_X> awaitAllSuccessfulOrThrow(Function<Throwable, R_X> esf) default booleanonComplete(StructuredTaskScope.SubtaskPREVIEW<T> subtask) Invoked by the thread that executed a subtask after the subtask completes successfully or fails with an exception.default booleanonFork(StructuredTaskScope.SubtaskPREVIEW<T> subtask) result()timeout()
-
Method Details
-
onFork
Invoked byfork(Callable)PREVIEW andfork(Runnable)PREVIEW when forking a subtask. The method is invoked before a thread is created to execute the subtask.- API Note:
- This method is invoked by the
forkmethods. It should not be invoked directly. - Implementation Requirements:
- The default implementation throws
NullPointerExceptionif the subtask isnull. It throwsIllegalArgumentExceptionif the subtask is not in theUNAVAILABLEPREVIEW state, it otherwise returnsfalse. - Parameters:
subtask- the subtask- Returns:
trueto cancel the scope, otherwisefalse
-
onComplete
Invoked by the thread that executed a subtask after the subtask completes successfully or fails with an exception. This method is not invoked by subtasks that complete after the scope is cancelled.- API Note:
- This method is invoked by subtasks when they complete. It should not be invoked directly.
- Implementation Requirements:
- The default implementation throws
NullPointerExceptionif the subtask isnull. It throwsIllegalArgumentExceptionif the subtask is not in theSUCCESSPREVIEW orFAILEDPREVIEW state, it otherwise returnsfalse. - Parameters:
subtask- the subtask- Returns:
trueto cancel the scope, otherwisefalse
-
result
Invoked by thejoin()PREVIEW method to produce the outcome (result or exception) after waiting for all subtasks to complete or the scope is cancelled. This method is not invoked if the scope was opened with a timeout and the timeout expires before or while waiting.This method will be called at most once, by the
join()method, to produce the outcome. The behavior of this method when invoked directly is undefined.- API Note:
- This method is invoked by the
join()method. It should not be invoked directly. - Returns:
- the result
- Throws:
R_X- if the outcome is an exception
-
timeout
Invoked by thejoin()PREVIEW method to produce the outcome (result or exception) when the scope was opened with a timeout and the timeout expires before or while waiting in thejoin()method.If the outcome is an exception, this method throws the exception with a
CancelledByTimeoutExceptionPREVIEW as thecause.This method will be called at most once, by the
join()method, to produce the outcome. The behavior of this method when invoked directly is undefined.- API Note:
- This method is invoked by the
join()method. It should not be invoked directly. - Returns:
- the result
- Throws:
R_X- with a cause ofCancelledByTimeoutException, if the outcome is an exception- Since:
- 27
-
allSuccessfulOrThrow
static <T, R_X extends Throwable> StructuredTaskScope.JoinerPREVIEW<T,List<T>, allSuccessfulOrThrowR_X> (Function<Throwable, R_X> esf) Returns a new Joiner that produces a list of all results when all subtasks complete successfully. TheJoinercancels the scope and causes thejoin()PREVIEW method to throw if any subtask fails.The
join()PREVIEW method of aStructuredTaskScopePREVIEW opened with this Joiner returns the list of the results, in the order that the subtasks were forkedPREVIEW, when all subtasks complete successfully. An empty list is returned if no subtasks were forked. If any subtask fails then theJoinercauses thejoin()method to throw the exception returned by the given exception supplying function when applied to the exception from the first subtask to fail. The function should return an exception with the exception from the failed subtask (the function argument) as the cause. If the function returnsnullthen it causes thejoin()method to throwNullPointerException.Timeout Handling: The
Joinercannot produce a result when the scope is cancelled by a timeout. If the scope was opened with a timeoutPREVIEW, and the timeout expires before or while waiting for all subtasks to complete successfully, then theJoinercauses thejoin()method to throw the exception returned by the exception supplying function when applied to aCancelledByTimeoutExceptionPREVIEW.- API Note:
- Joiners returned by this method are suited to cases where all subtasks
return a result of the same type. It removes the need for bookkeeping
and the need to keep a reference to the
SubtaskPREVIEW objects returned by thefork(Callable)PREVIEW method. Joiners returned byawaitAllSuccessfulOrThrow(Function)andawaitAllSuccessfulOrThrow()are suited to cases where the subtasks return results of different types and where it is necessary to keep a reference to theSubtaskobjects.The following example is a method that opens a
StructuredTaskScopewith a Joiner created withallSuccessfulOrThrow(Function). The method is invoked with a collection of callables. It forksPREVIEW a subtask to execute each callable, waits injoin()PREVIEW for all subtasks to complete successfully, and then returns a list of the results. It throws the runtime exceptionCompletionExceptionif any subtask fails, with the exception from the first subtask to fail as the cause.<T> List<T> invokeAll(Collection<Callable<T>> tasks) throws InterruptedException { try (var scope = StructuredTaskScope.open( Joiner.<T, CompletionException>allSuccessfulOrThrow(CompletionException::new))) { tasks.forEach(scope::fork); List<T> results = scope.join(); return results; } } - Type Parameters:
T- the result type of subtasksR_X- the type of the exception thrown by thejoin()PREVIEW method- Parameters:
esf- the exception supplying function- Returns:
- a new Joiner that produces a list of all results when all subtasks complete successfully
- Since:
- 27
- See Also:
-
allSuccessfulOrThrow
Returns a new Joiner that produces a list of all results when all subtasks complete successfully. TheJoinercancels the scope and causes thejoin()PREVIEW method to throwExecutionExceptionif any subtask fails.The
join()PREVIEW method of aStructuredTaskScopePREVIEW opened with this Joiner returns the list of the results, in the order that the subtasks were forkedPREVIEW, when all subtasks complete successfully. An empty list is returned if no subtasks were forked. If any subtask fails then the Joiner causes thejoin()method to throwExecutionExceptionwith the exception from the first subtask to fail as the cause.Timeout Handling: The
Joinercannot produce a result when the scope is cancelled by a timeout. If the scope was opened with a timeoutPREVIEW, and the timeout expires before or while waiting for all subtasks to complete successfully, then theJoinercauses thejoin()method to throwExecutionExceptionwith aCancelledByTimeoutExceptionPREVIEW as the cause.- Implementation Requirements:
- A Joiner returned by this method is equivalent to invoking
allSuccessfulOrThrow(ExecutionException::new). - Type Parameters:
T- the result type of subtasks- Returns:
- a new Joiner that produces a list of all results when all subtasks complete successfully
-
anySuccessfulOrThrow
static <T, R_X extends Throwable> StructuredTaskScope.JoinerPREVIEW<T,T, anySuccessfulOrThrowR_X> (Function<Throwable, R_X> esf) Returns a new Joiner that produces the result of any successful subtask. TheJoinercancels the scope when a subtask completes successfully. It causes thejoin()PREVIEW method to throw if all subtasks fail.The
join()PREVIEW method of aStructuredTaskScopePREVIEW opened with this Joiner returns the result of a successful subtask. If a subtask completes successfully then the scope is cancelled and thejoin()method returns its result. If all subtasks fail then the Joiner causes thejoin()method to throw the exception returned by the given exception supplying function when applied to the exception from one of the failed subtasks. The function should return an exception with the exception from the failed subtask (the function argument) as the cause. If the function returnsnullthen it causes thejoin()method to throwNullPointerException. If no subtasks were forked then the Joiner causes thejoin()method to throw the exception returned by the function when applied to an instance ofNoSuchElementException.Timeout Handling: The
Joinercannot produce a result when the scope is cancelled by a timeout. If the scope was opened with a timeoutPREVIEW, and the timeout expires before or while waiting for a subtask to complete successfully, then theJoinercauses thejoin()method to throw the exception returned by the exception supplying function when applied to aCancelledByTimeoutExceptionPREVIEW.- API Note:
- The following example is a method that opens a
StructuredTaskScopewith a Joiner created withanySuccessfulOrThrow(Function). The method is invoked with a collection of callables. It forksPREVIEW a subtask to execute each callable, waits injoin()PREVIEW for any subtask to complete successfully, returning its result. It throws the runtime exceptionCompletionExceptionif all subtasks fail, with the exception from a failed subtask as the cause.<T> T invokeAny(Collection<Callable<T>> tasks) throws InterruptedException { try (var scope = StructuredTaskScope.open( Joiner.<T, CompletionException>anySuccessfulOrThrow(CompletionException::new))) { tasks.forEach(scope::fork); T result = scope.join(); return result; } } - Type Parameters:
T- the result type of subtasksR_X- the type of the exception thrown by thejoin()PREVIEW method- Parameters:
esf- the exception supplying function- Returns:
- a new Joiner that produces the result of any successful subtask
- Since:
- 27
- See Also:
-
anySuccessfulOrThrow
Returns a new Joiner that produces the result of any successful subtask. TheJoinercancels the scope when a subtask completes successfully. It causes thejoin()PREVIEW method to throwExecutionExceptionif all subtasks fail.The
join()PREVIEW method of aStructuredTaskScopePREVIEW opened with this Joiner returns the result of a successful subtask. If a subtask completes successfully then the scope is cancelled and thejoin()method returns its result. If all subtasks fail then the Joiner causes thejoin()method to throwExecutionExceptionwith the exception from one of the failed subtasks as the cause. If no subtasks were forked then theJoinercauses thejoin()method to throwExecutionExceptionwithNoSuchElementExceptionas the cause.Timeout Handling: The
Joinercannot produce a result when the scope is cancelled by a timeout. If the scope was opened with a timeoutPREVIEW, and the timeout expires before or while waiting for a subtask to complete successfully, then theJoinercauses thejoin()method to throwExecutionExceptionwith aCancelledByTimeoutExceptionPREVIEW as the cause.- Implementation Requirements:
- A Joiner returned by this method is equivalent to invoking
anySuccessfulOrThrow(ExecutionException::new). - Type Parameters:
T- the result type of subtasks- Returns:
- a new Joiner that produces the result of any successful subtask
- Since:
- 26
-
awaitAllSuccessfulOrThrow
static <T, R_X extends Throwable> StructuredTaskScope.JoinerPREVIEW<T,Void, awaitAllSuccessfulOrThrowR_X> (Function<Throwable, R_X> esf) Returns a new Joiner that causes thejoin()PREVIEW method to wait for all subtasks to complete successfully. TheJoinercancels the scope and causes thejoin()PREVIEW method to throw if any subtask fails.The
join()PREVIEW method of aStructuredTaskScopePREVIEW opened with this Joiner returnsnullwhen all subtasks complete successfully. If any subtask fails then the Joiner causes thejoin()method to throw the exception returned by the given exception supplying function when applied to the exception from the first subtask to fail. The function should return an exception with the exception from the failed subtask (the function argument) as the cause. If the function returnsnullthen it causes thejoin()method to throwNullPointerException.Timeout Handling: The
Joinercannot produce a result when the scope is cancelled by a timeout. If the scope was opened with a timeoutPREVIEW, and the timeout expires before or while waiting for all subtasks to complete successfully, then theJoinercauses thejoin()method to throw the exception returned by the exception supplying function when applied to aCancelledByTimeoutExceptionPREVIEW.- API Note:
- Joiners returned by this method are suited to cases where subtasks
return results of different types and where it is necessary to keep a reference
to each
SubtaskPREVIEW. Joiners returned byallSuccessfulOrThrow(Function)andallSuccessfulOrThrow()are suited to cases where the subtasks return a result of the same type.The following example opens a
StructuredTaskScopewith a Joiner created withawaitAllSuccessfulOrThrow(). It forksPREVIEW two subtasks, then waits injoin()PREVIEW for both subtasks to complete successfully or either subtask to fail. If both subtasks complete successfully then it invokesSubtask.get()PREVIEW on both subtasks to get their results. It throws the runtime exceptionCompletionExceptionif any subtask fails, with the exception from a failed subtask as the cause.try (var scope = StructuredTaskScope.open( Joiner.awaitAllSuccessfulOrThrow(CompletionException::new))) { Subtask<String> subtask1 = scope.fork(callable1); Subtask<Integer> subtask2 = scope.fork(callable2); // throws CompletionException if either subtask fails scope.join(); // both subtasks completed successfully var result = new MyResult(subtask1.get(), subtask2.get()); } - Type Parameters:
T- the result type of subtasksR_X- the type of the exception thrown by thejoin()PREVIEW method- Parameters:
esf- the exception supplying function- Returns:
- a new Joiner that causes the
join()PREVIEW method to wait for all subtasks to complete successfully - Since:
- 27
-
awaitAllSuccessfulOrThrow
static <T> StructuredTaskScope.JoinerPREVIEW<T, Void, ExecutionException> awaitAllSuccessfulOrThrow()Returns a new Joiner that causes thejoin()PREVIEW method to wait for all subtasks to complete successfully. TheJoinercancels the scope and causes thejoin()PREVIEW method to throwExecutionExceptionif any subtask fails.The
join()PREVIEW method of aStructuredTaskScopePREVIEW opened with this Joiner returnsnullwhen all subtasks complete successfully. If any subtask fails then the Joiner causes thejoin()method to throwExecutionExceptionwith the exception from the first subtask to fail as the cause.Timeout Handling: The
Joinercannot produce a result when the scope is cancelled by a timeout. If the scope was opened with a timeoutPREVIEW, and the timeout expires before or while waiting for all subtasks to complete successfully, then theJoinercauses thejoin()method to throwExecutionExceptionwith aCancelledByTimeoutExceptionPREVIEW as the cause.- Implementation Requirements:
- A Joiner returned by this method is equivalent to invoking
awaitAllSuccessfulOrThrow(ExecutionException::new). - Type Parameters:
T- the result type of subtasks- Returns:
- a new Joiner that causes the
join()PREVIEW method to wait for all subtasks to complete successfully - See Also:
-
allUntil
static <T> StructuredTaskScope.JoinerPREVIEW<T, List<StructuredTaskScope.SubtaskPREVIEW<T>>, RuntimeException> allUntil(Predicate<? super StructuredTaskScope.SubtaskPREVIEW<T>> isDone) Returns a new Joiner that produces a list of all subtasks when all subtasks complete or evaluating a predicate on a completed subtask causes the scope to be cancelled. TheJoinerdoes not cause thejoin()PREVIEW method to throw if subtasks fail or a configured timeoutPREVIEW expires. This method can be used to create aJoinerthat implements a cancellation policy.The
join()PREVIEW method of aStructuredTaskScopePREVIEW opened with this Joiner returns a list of all subtasks, in the order that they were forkedPREVIEW, when all subtasks complete or the scope is cancelled. The returned list may contain subtasks that completed (in theSUCCESSPREVIEW orFAILEDPREVIEW state), or subtasks in theUNAVAILABLEPREVIEW state if they were forked or completed after the scope was cancelled. The scope is cancelled if the given predicate evaluates totrue, or a configured timeout expires before or while waiting in thejoin()method.The given
Predicate'stest(Object)method is invoked on a completed subtask by the thread that executed the subtask. The method is invoked after the subtask completes (successfully or with an exception) before the thread terminates. The scope is cancelled if thetestmethod returnstrue. Thetestmethod must be thread safe. It may be invoked concurrently from several threads as multiple subtasks can complete at the same time. If the method throws an exception or error, the thread invokes the uncaught exception handler with the exception or error before the thread terminates.Timeout Handling: If used with a scope that has a timeoutPREVIEW set, and the timeout expires before all subtasks complete then the
join()method returns the list of all subtasks. It does not throw an exception. Subtasks that did not complete before the timeout expires will be in theUNAVAILABLEstate.- API Note:
- The following example uses
allUntilto create a Joiner that cancels the scope when two or more subtasks fail.class CancelAfterTwoFailures implements Predicate<Subtask<?>> { private final AtomicInteger failedCount = new AtomicInteger(); @Override public boolean test(Subtask<?> subtask) { return subtask.state() == Subtask.State.FAILED && failedCount.incrementAndGet() >= 2; } } var joiner = Joiner.<String>allUntil(new CancelAfterTwoFailures());The following example uses
allUntilto create a Joiner that cancels the scope when any subtask completes successfully. The subtasks are grouped according to their state to produce a map with up to three key-value mappings. The map key is the subtask state, the value is the list of subtasks in that state.Predicate<Subtask<?>> isSuccessful = s -> s.state() == Subtask.State.SUCCESS; try (var scope = StructuredTaskScope.open(Joiner.<String>allUntil(isSuccessful))) { tasks.forEach(scope::fork); Map<Subtask.State, List<Subtask<String>>> subtasksByState = scope.join() .stream() .collect(Collectors.groupingBy(Subtask::state)); }The following example is a method that uses
allUntilto create a Joiner that does not cancel the scope. The method waits for all subtasks to complete or a timeout to expire. It returns a list of all subtasks, in the same order as the collection of callables, even if the timeout expires before or while waiting injoin().<T> List<Subtask<T>> invokeAll(Collection<Callable<T>> tasks, Duration timeout) throws InterruptedException { try (var scope = StructuredTaskScope.open(Joiner.<T>allUntil(_ -> false), cf -> cf.withTimeout(timeout))) { tasks.forEach(scope::fork); return scope.join(); } } - Type Parameters:
T- the result type of subtasks- Parameters:
isDone- the predicate to evaluate completed subtasks- Returns:
- a new Joiner that produces a list of all subtasks when all subtasks complete or evaluating a predicate on a completed subtask causes the scope to be cancelled
-
Joinerwhen preview features are enabled.