StructuredTaskScope.Joiner (Java SE 26 & JDK 26)
Description: declaration: module: java.base, package: java.util.concurrent, interface: StructuredTaskScope, interface: Joiner
Keywords: java.util.concurrent.StructuredTaskScope.Joiner interface

# Interface StructuredTaskScope.Joiner<T,R>

Type Parameters:
  `T` - the result type of subtasks executed in the scope
  `R` - the result type of the scope

Enclosing interface:
  `StructuredTaskScopePREVIEW<T,R>`

public static interface StructuredTaskScope.Joiner<T,R>
`Joiner` is a preview API of the Java platform.
Programs can only use `Joiner` when preview features are enabled.
Preview features may be removed in a future release, or upgraded to permanent features of the Java platform.
An object used with a `StructuredTaskScope`PREVIEW to handle subtask completion and produce the result for the scope owner waiting in the `join`PREVIEW method for subtasks to complete.

Joiner defines static methods to create `Joiner` objects for common cases:

- `allSuccessfulOrThrow()` creates a `Joiner` that yields a list of all results for `join` to return when all subtasks complete successfully. It cancels the scope and causes `join` to throw if any subtask fails.
- `anySuccessfulOrThrow()` creates a `Joiner` that yields the result of the first subtask to succeed for `join` to return. It causes `join` to throw if all subtasks fail.
- `awaitAllSuccessfulOrThrow()` creates a `Joiner` that waits for all successful subtasks. It cancels the scope and causes `join` to throw if any subtask fails.
- `awaitAll()` creates a `Joiner` that waits for all subtasks to complete. It does not cancel the scope or cause `join` to throw.

In addition to the methods to create `Joiner` objects for common cases, the `allUntil(Predicate)` method is defined to create a `Joiner` that yields a list of all subtasks. It is created with a `Predicate` that determines if the scope should continue or be cancelled. This `Joiner` can be built upon to create custom policies that cancel the scope based on some condition.

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 if 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 result (or exception) for the `join` method.

If a `StructuredTaskScope` is opened with a timeoutPREVIEW, and the timeout expires before or while waiting in `join()`PREVIEW, then the scope is cancelled, and the `Joiners`'s `onTimeout()` method is invoked to notify the `Joiner` and optionally throw `TimeoutException`PREVIEW. If the `onTimeout()` method does not throw then the `join()` method will invoke the `result()` method to produce a result. This result may be based on the outcome of subtasks that completed before the timeout expired.

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 `Joiner` object is created for each `StructuredTaskScope`. `Joiner` objects should never be shared with different scopes or re-used after a scope is closed.

  Designing a `Joiner` should take into account the code at the use-site where the results from the `join`PREVIEW method are processed. It should be clear what the `Joiner` does vs. the application code at the use-site. In general, the `Joiner` implementation is not the place for "business logic". A `Joiner` should be designed to be as general purpose as possible.

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, the `onComplete` method may be called concurrently with the scope owner thread invoking the `onFork(Subtask)` or `onTimeout()` methods.
Since:
  25
See Also:
  - `StructuredTaskScope.open(Joiner)`PREVIEW

- ## Method Summary

  Modifier and Type
  Method
  Description
  `static <T> StructuredTaskScope.JoinerPREVIEW<T,List<T>>`
  `allSuccessfulOrThrow()`
  Returns a new Joiner object that yields a list of all results when all subtasks complete successfully.
  `static <T> StructuredTaskScope.JoinerPREVIEW<T, List<StructuredTaskScope.SubtaskPREVIEW<T>>>`
  `allUntil(Predicate<StructuredTaskScope.SubtaskPREVIEW<T>> isDone)`
  Returns a new Joiner object that yields a list of all subtasks when all subtasks complete or a predicate returns `true` to cancel the scope.
  `static <T> StructuredTaskScope.JoinerPREVIEW<T,T>`
  `anySuccessfulOrThrow()`
  Returns a new Joiner object that yields the result of any subtask that completed successfully.
  `static <T> StructuredTaskScope.JoinerPREVIEW<T,Void>`
  `awaitAll()`
  Returns a new Joiner object that waits for all subtasks to complete.
  `static <T> StructuredTaskScope.JoinerPREVIEW<T,Void>`
  `awaitAllSuccessfulOrThrow()`
  Returns a new Joiner object that waits for subtasks to complete successfully.
  `default boolean`
  `onComplete(StructuredTaskScope.SubtaskPREVIEW<T> subtask)`
  Invoked by the thread started to execute a subtask after the subtask completes successfully or fails with an exception.
  `default boolean`
  `onFork(StructuredTaskScope.SubtaskPREVIEW<T> subtask)`
  Invoked by `fork(Callable)`PREVIEW and `fork(Runnable)`PREVIEW when forking a subtask.
  `default void`
  `onTimeout()`
  Invoked by the `join()`PREVIEW method if the scope was opened with a timeout, and the timeout expires before or while waiting in the `join` method.
  `R`
  `result()`
  Invoked by the `join()`PREVIEW method to produce the result (or exception) after waiting for all subtasks to complete or the scope cancelled.

- ## Method Details

  - ### onFork

    default boolean onFork(StructuredTaskScope.SubtaskPREVIEW<T> subtask)
    Invoked by `fork(Callable)`PREVIEW and `fork(Runnable)`PREVIEW when forking a subtask. The method is invoked before a thread is created to run the subtask.
    API Note:
      This method is invoked by the `fork` methods. It should not be invoked directly.
    Implementation Requirements:
      The default implementation throws `NullPointerException` if the subtask is `null`. It throws `IllegalArgumentException` if the subtask is not in the `UNAVAILABLE`PREVIEW state, it otherwise returns `false`.
    Parameters:
      `subtask` - the subtask
    Returns:
      `true` to cancel the scope, otherwise `false`

  - ### onComplete

    default boolean onComplete(StructuredTaskScope.SubtaskPREVIEW<T> subtask)
    Invoked by the thread started to execute a subtask after the subtask completes successfully or fails with an exception. This method is not invoked if a subtask completes 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 `NullPointerException` if the subtask is `null`. It throws `IllegalArgumentException` if the subtask is not in the `SUCCESS`PREVIEW or `FAILED`PREVIEW state, it otherwise returns `false`.
    Parameters:
      `subtask` - the subtask
    Returns:
      `true` to cancel the scope, otherwise `false`

  - ### onTimeout

    default void onTimeout()
    Invoked by the `join()`PREVIEW method if the scope was opened with a timeout, and the timeout expires before or while waiting in the `join` method.
    API Note:
      This method is intended for `Joiner` implementations that do not throw `TimeoutException`PREVIEW, or require a notification when the timeout expires before or while waiting in `join`.

      This method is invoked by the `join` method. It should not be invoked directly.

    Implementation Requirements:
      The default implementation throws `TimeoutException`PREVIEW.
    Throws:
      `StructuredTaskScope.TimeoutExceptionPREVIEW` - for `join` to throw
    Since:
      26

  - ### result

    R result() throws Throwable
    Invoked by the `join()`PREVIEW method to produce the result (or exception) after waiting for all subtasks to complete or the scope cancelled. The result from this method is returned by the `join` method. If this method throws, then `join` throws `StructuredTaskScope.FailedException`PREVIEW with the exception thrown by this method as the cause.

    In normal usage, this method will be called at most once by the `join` method to produce the result (or exception). 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:
      `Throwable` - the exception

  - ### allSuccessfulOrThrow

    static <T> StructuredTaskScope.JoinerPREVIEW<T,List<T>> allSuccessfulOrThrow()
    Returns a new Joiner object that yields a list of all results when all subtasks complete successfully. The `Joiner` cancels the scope and causes `join` to throw if any subtask fails.

    If all subtasks complete successfully then the joiner's `result()` method returns a list of all results, in the order that the subtasks were forked, for the `join()`PREVIEW to return. If the scope was opened with a timeoutPREVIEW, and the timeout expires before or while waiting for all subtasks to complete, then the `join` method throws `TimeoutException`.

    API Note:
      Joiners returned by this method are suited to cases where all subtasks return a result of the same type. Joiners returned by `awaitAllSuccessfulOrThrow()` are suited to cases where the subtasks return results of different types.
    Type Parameters:
      `T` - the result type of subtasks
    Returns:
      a new Joiner object that yields a list of all results when all subtasks complete successfully

  - ### anySuccessfulOrThrow

    static <T> StructuredTaskScope.JoinerPREVIEW<T,T> anySuccessfulOrThrow()
    Returns a new Joiner object that yields the result of any subtask that completed successfully. The `Joiner` causes `join` to throw if all subtasks fail.

    The joiner's `result()` method returns the result of a subtask, that completed successfully, for the `join()`PREVIEW to return. If all subtasks fail then the `result` method throws the exception from one of the failed subtasks. The `result` method throws `NoSuchElementException` if no subtasks were forked. If the scope was opened with a timeoutPREVIEW, and the timeout expires before or while waiting for any subtask to complete successfully, then the `join` method throws `TimeoutException`.

    Type Parameters:
      `T` - the result type of subtasks
    Returns:
      a new Joiner object that yields the result of any subtask that completed successfully
    Since:
      26

  - ### awaitAllSuccessfulOrThrow

    static <T> StructuredTaskScope.JoinerPREVIEW<T,Void> awaitAllSuccessfulOrThrow()
    Returns a new Joiner object that waits for subtasks to complete successfully. The `Joiner` cancels the scope and causes `join` to throw if any subtask fails.

    The joiner's `result` method returns `null` if all subtasks complete successfully, or throws the exception from the first subtask to fail. If the scope was opened with a timeoutPREVIEW, and the timeout expires before or while waiting for all subtasks to complete, then the `join` method throws `TimeoutException`.

    API Note:
      Joiners returned by this method are suited to cases where subtasks return results of different types. Joiners returned by `allSuccessfulOrThrow()` are suited to cases where the subtasks return a result of the same type.
    Type Parameters:
      `T` - the result type of subtasks
    Returns:
      a new Joiner object that waits for subtasks to complete successfully

  - ### awaitAll

    static <T> StructuredTaskScope.JoinerPREVIEW<T,Void> awaitAll()
    Returns a new Joiner object that waits for all subtasks to complete. The `Joiner` does not cancel the scope if a subtask fails.

    The joiner's `result` method returns `null`. If the scope was opened with a timeoutPREVIEW, and the timeout expires before or while waiting for all subtasks to complete, then the `join` method throws `TimeoutException`.

    API Note:
      This Joiner is useful for cases where subtasks make use of side-effects rather than return results or fail with exceptions. The `fork(Runnable)`PREVIEW method can be used to fork subtasks that do not return a result.

      This Joiner can also be used for fan-in scenarios where subtasks are forked to handle incoming connections and the number of subtasks is unbounded. In this example, the thread executing the `acceptLoop` method will only stop when interrupted or the listener socket is closed asynchronously.

            void acceptLoop(ServerSocket listener) throws IOException, InterruptedException {
                try (var scope = StructuredTaskScope.open(Joiner.<Socket>awaitAll())) {
                    while (true) {
                        Socket socket = listener.accept();
                        scope.fork(() -> handle(socket));
                    }
                }
            }

    Type Parameters:
      `T` - the result type of subtasks
    Returns:
      a new Joiner object that waits for all subtasks to complete

  - ### allUntil

    static <T> StructuredTaskScope.JoinerPREVIEW<T, List<StructuredTaskScope.SubtaskPREVIEW<T>>> allUntil(Predicate<StructuredTaskScope.SubtaskPREVIEW<T>> isDone)
    Returns a new Joiner object that yields a list of all subtasks when all subtasks complete or a predicate returns `true` to cancel the scope.

    The joiner's `onComplete(Subtask)` method invokes the predicate's `test` method with the subtask that completed successfully or failed with an exception. If the `test` method returns `true` then the scope is cancelled. The `test` method must be thread safe as it may be invoked concurrently from several threads. If the `test` method completes with an exception or error, then the thread that executed the subtask invokes the uncaught exception handler with the exception or error before the thread terminates.

    The joiner's `result()` method returns the list of all subtasks, in fork order. The list may contain subtasks that have completed (in `SUCCESS`PREVIEW or `FAILED`PREVIEW state) or subtasks in the `UNAVAILABLE`PREVIEW state if the scope was cancelled before all subtasks were forked or completed.

    The joiner's `onTimeout()` method does nothing. If configured with a timeoutPREVIEW, and the timeout expires before or while waiting in `join`PREVIEW, then the `result()` method returns the list of all subtasks. Subtasks that did not complete before the timeout expired will be in the `UNAVAILABLE`PREVIEW state.

    The following example uses this method to create a `Joiner` that cancels the scope when two or more subtasks fail.

           class CancelAfterTwoFailures<T> implements Predicate<Subtask<T>> {
                private final AtomicInteger failedCount = new AtomicInteger();
                @Override
                public boolean test(Subtask<T> subtask) {
                    return subtask.state() == Subtask.State.FAILED
                            && failedCount.incrementAndGet() >= 2;
                }
            }

            var joiner = Joiner.allUntil(new CancelAfterTwoFailures<String>());

    The following example uses `allUntil` to wait for all subtasks to complete without any cancellation. This is similar to `awaitAll()` except that it yields a list of the completed subtasks.

           <T> List<Subtask<T>> invokeAll(Collection<Callable<T>> tasks) throws InterruptedException {
               try (var scope = StructuredTaskScope.open(Joiner.<T>allUntil(_ -> false))) {
                   tasks.forEach(scope::fork);
                   return scope.join();
               }
           }

    The following example uses `allUntil` to get the results of all subtasks that complete successfully within a timeout period.

           <T> List<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()
                        .stream()
                        .filter(s -> s.state() == Subtask.State.SUCCESS)
                        .map(Subtask::get)
                        .toList();
                }
            }

    Type Parameters:
      `T` - the result type of subtasks
    Parameters:
      `isDone` - the predicate to evaluate completed subtasks
    Returns:
      a new Joiner object that yields a list of all subtasks when all subtasks complete or a predicate returns `true` to cancel the scope