diff --git a/api/src/main/java/jakarta/enterprise/concurrent/ManagedExecutorService.java b/api/src/main/java/jakarta/enterprise/concurrent/ManagedExecutorService.java index 022fc05e..09af3319 100644 --- a/api/src/main/java/jakarta/enterprise/concurrent/ManagedExecutorService.java +++ b/api/src/main/java/jakarta/enterprise/concurrent/ManagedExecutorService.java @@ -16,7 +16,10 @@ package jakarta.enterprise.concurrent; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; import java.util.concurrent.ExecutorService; +import java.util.function.Supplier; /** * A manageable version of a {@link java.util.concurrent.ExecutorService}. @@ -162,11 +165,187 @@ * // Some account data... * } * - *

- * + * + *

ManagedExecutorService provides various methods which correspond to the + * static methods of {@link java.util.concurrent.CompletableFuture} and its + * constructor/newIncompleteFuture method, + * enabling you to create completion stages that are backed by the ManagedExecutorService + * as the default asynchronous execution facility, both for those stages + * as well as all dependent stages that are created from those, and so on. + * This allows you to create pipelines of completion stage actions that run + * with consistent and predictable thread context, regardless of which thread each + * dependent action ends up running on.

+ * + *

Example:

+ *
+ * ManagedExectorService executor = InitialContext.doLookup("java:comp/DefaultManagedExecutorService");
+ * ...
+ * CompletableFuture<Integer> future = executor
+ *    .supplyAsync(supplier)
+ *    .thenApply(function1)
+ *    .thenApplyAsync(function2)
+ *    ...
+ * 
+ * 
+ * + *

Context propagation to completion stages that are backed by a + * ManagedExecutorService must be done in a consistent + * and predictable manner, which is defined as follows,

+ * + * + * + *

Each type of thread context is applied (either as cleared or previously captured) + * to the thread that runs the action. The applied thread context is removed after the action + * completes, whether successfully or exceptionally, restoring the thread's prior context.

+ * + *

When dependent stages are created from the completion stage, and likewise from any dependent stages + * created from those, and so on, thread context is captured or cleared in the same manner. + * This guarantees that the action performed by each stage always runs under the thread context + * of the code that creates the completion stage, unless the user explicitly overrides this by supplying a + * pre-contextualized action.

+ * + *

Completion stages that are backed by a ManagedExecutorService must raise + * {@link java.lang.IllegalArgumentException} if supplied with an action that implements + * {@link ManagedTask}.

+ * * @since 1.0 */ public interface ManagedExecutorService extends ExecutorService { + /** + *

Returns a new {@link java.util.concurrent.CompletableFuture} + * that is already completed with the specified value.

+ * + *

This executor is the default asynchronous execution facility for the new completion stage + * that is returned by this method and all dependent stages that are created from it, + * and all dependent stages that are created from those, as so forth.

+ * + * @param value result with which the completable future is completed. + * @param result type of the completable future. + * @return the new completable future. + */ + CompletableFuture completedFuture(U value); + + /** + *

Returns a new {@link java.util.concurrent.CompletionStage} + * that is already completed with the specified value.

+ * + *

This executor is the default asynchronous execution facility for the new completion stage + * that is returned by this method and all dependent stages that are created from it, + * and all dependent stages that are created from those, as so forth.

+ * + * @param value result with which the completion stage is completed. + * @param result type of the completion stage. + * @return the new completion stage. + */ + CompletionStage completedStage(U value); + + /** + *

+ * Returns a new {@link java.util.concurrent.CompletableFuture} + * that is completed by the completion of the + * specified stage. + *

+ * + *

+ * The new completable future is backed by the ManagedExecutorService upon which copy is invoked, + * which serves as the default asynchronous execution facility + * for the new stage and all dependent stages created from it, and so forth. + *

+ * + *

+ * When dependent stages are created from the new completable future, thread context is captured + * and/or cleared by the ManagedExecutorService. This guarantees that the action + * performed by each stage always runs under the thread context of the code that creates the stage, + * unless the user explicitly overrides by supplying a pre-contextualized action. + *

+ * + *

+ * Invocation of this method does not impact thread context propagation for the supplied + * completable future or any other dependent stages directly created from it. + *

+ * + * @param completable future result type. + * @param stage a completable future whose completion triggers completion of the new completable + * future that is created by this method. + * @return the new completable future. + */ + CompletableFuture copy(CompletableFuture stage); + + /** + *

+ * Returns a new {@link java.util.concurrent.CompletionStage} + * that is completed by the completion of the + * specified stage. + *

+ * + *

+ * The new completion stage is backed by the ManagedExecutorService upon which copy is invoked, + * which serves as the default asynchronous execution facility + * for the new stage and all dependent stages created from it, and so forth. + *

+ * + *

+ * When dependent stages are created from the new completion stage, thread context is captured + * and/or cleared by the ManagedExecutorService. This guarantees that the action + * performed by each stage always runs under the thread context of the code that creates the stage, + * unless the user explicitly overrides by supplying a pre-contextualized action. + *

+ * + *

+ * Invocation of this method does not impact thread context propagation for the supplied + * stage or any other dependent stages directly created from it. + *

+ * + * @param completion stage result type. + * @param stage a completion stage whose completion triggers completion of the new stage + * that is created by this method. + * @return the new completion stage. + */ + CompletionStage copy(CompletionStage stage); + + /** + *

Returns a new {@link java.util.concurrent.CompletableFuture} + * that is already exceptionally completed with the specified Throwable.

+ * + *

This executor is the default asynchronous execution facility for the new completion stage + * that is returned by this method and all dependent stages that are created from it, + * and all dependent stages that are created from those, as so forth.

+ * + * @param ex exception or error with which the completable future is completed. + * @param result type of the completable future. + * @return the new completable future. + */ + CompletableFuture failedFuture(Throwable ex); + + /** + *

Returns a new {@link java.util.concurrent.CompletionStage} + * that is already exceptionally completed with the specified Throwable.

+ * + *

This executor is the default asynchronous execution facility for the new completion stage + * that is returned by this method and all dependent stages that are created from it, + * and all dependent stages that are created from those, as so forth.

+ * + * @param ex exception or error with which the completion stage is completed. + * @param result type of the completion stage. + * @return the new completion stage. + */ + CompletionStage failedStage(Throwable ex); + /** * Returns a {@link ContextService} which has the same propagation settings as this ManagedExecutorService * and uses this ManagedExecutorService as the default asynchronous execution facility for @@ -176,4 +355,45 @@ public interface ManagedExecutorService extends ExecutorService { * @return a ContextService with the same propagation settings as this ManagedExecutorService. */ public ContextService getContextService(); + + /** + *

Returns a new incomplete {@link java.util.concurrent.CompletableFuture}.

+ * + *

This executor is the default asynchronous execution facility for the new completion stage + * that is returned by this method and all dependent stages that are created from it, + * and all dependent stages that are created from those, as so forth.

+ * + * @param result type of the completable future. + * @return the new completable future. + */ + CompletableFuture newIncompleteFuture(); + + /** + *

Returns a new {@link java.util.concurrent.CompletableFuture} + * that is completed by a task running in this executor + * after it runs the given action.

+ * + *

This executor is the default asynchronous execution facility for the new completion stage + * that is returned by this method and all dependent stages that are created from it, + * and all dependent stages that are created from those, as so forth.

+ * + * @param runnable the action to run before completing the returned completion stage. + * @return the new completable future. + */ + CompletableFuture runAsync(Runnable runnable); + + /** + *

Returns a new {@link java.util.concurrent.CompletableFuture} + * that is completed by a task running in this executor + * after it runs the given action.

+ * + *

This executor is the default asynchronous execution facility for the new completion stage + * that is returned by this method and all dependent stages that are created from it, + * and all dependent stages that are created from those, as so forth.

+ * + * @param supplier an action returning the value to be used to complete the returned completion stage. + * @param result type of the supplier and returned completable stage. + * @return the new completable future. + */ + CompletableFuture supplyAsync(Supplier supplier); } diff --git a/specification/src/main/asciidoc/jakarta-concurrency.adoc b/specification/src/main/asciidoc/jakarta-concurrency.adoc index 63e5a67e..1248d241 100644 --- a/specification/src/main/asciidoc/jakarta-concurrency.adoc +++ b/specification/src/main/asciidoc/jakarta-concurrency.adoc @@ -1,7 +1,7 @@ :sectnums: = Jakarta Concurrency Specification, Version 2.0 -Copyright (c) 2013, 2020 Oracle and/or its affiliates. All rights reserved. +Copyright (c) 2013, 2021 Oracle and/or its affiliates. All rights reserved. Oracle and Java are registered trademarks of Oracle and/or its affiliates. Other names may be trademarks of their respective owners. @@ -194,6 +194,16 @@ as "tasks" will be referred to throughout the specification: ** `call()` * `java.lang.Runnable` ** `run()` +* `java.util.function.BiConsumer` +** `accept(T, U)` +* `java.util.function.BiFunction` +** `apply(T, U)` +* `java.util.function.Consumer` +** `accept(T)` +* `java.util.function.Function` +** `apply(T)` +* `java.util.function.Supplier` +** `get()` ===== Optional Contextual Invocation Points @@ -219,7 +229,9 @@ methods. These methods can be made contextual through the ContextService Tasks are concrete implementations of the Java SE `java.util.concurrent.Callable` and `java.lang.Runnable` interfaces (see the -Javadoc for `java.util.concurrent.ExecutorService`). Tasks are units of +Javadoc for `java.util.concurrent.ExecutorService`) as well as the various +functional interfaces that serve as completion stage actions (see the +JavaDoc for `java.util.concurrent.CompletionStage`). Tasks are units of work that represent a computation or some business logic. A contextual object is any Java object instance that has a particular @@ -234,7 +246,8 @@ using CDI beans as tasks._ ==== When a task instance is submitted to a managed instance of an -ExecutorService, the task becomes a contextual task. When the contextual +ExecutorService or a managed CompletionStage, +the task becomes a contextual task. When the contextual task runs, the task behaves as if it were still running in the container it was submitted with. @@ -352,7 +365,9 @@ component’s environment for the resource type. For example, all `java:comp/env/concurrent` subcontext. Components create task classes by implementing the `java.lang.Runnable` or -`java.util.concurrent.Callable` interfaces. These task classes are +`java.util.concurrent.Callable` interfaces, or any of the functional +interfaces that can be supplied to a `java.util.concurrent.CompletionStage`. +These task classes are typically stored with the Jakarta EE application component. Task classes can optionally implement the @@ -365,8 +380,10 @@ any current transaction on the thread and to provide identity information. Task instances are submitted to a `ManagedExecutorService` instance using -any of the defined `submit()`, `execute()`, `invokeAll()`, or `invokeAny()` -methods. Task instances will run as an extension of the Jakarta EE +any of the defined `submit()`, `execute()`, `invokeAll()`, `invokeAny()`, +`runAsync()`, or `supplyAsync()` methods. Task instances can also be +submitted to a `CompletionStage` that is backed by a `ManagedExecutorService`. +Task instances will run as an extension of the Jakarta EE container instance that submitted the task and may interact with Jakarta EE resources as defined in other sections of this specification. @@ -1055,8 +1072,10 @@ typically stored with the Jakarta EE application component. Task instances are submitted to a `ManagedScheduledExecutorService` instance using any of the defined `submit()`, `execute()`, `invokeAll()`, -`invokeAny()`, `schedule()`, `scheduleAtFixedRate()` or -`scheduleWithFixedDelay()` methods. Task instances will run as an +`invokeAny()`, `runAsync()`, `supplyAsync()`, `schedule()`, +`scheduleAtFixedRate()`, or `scheduleWithFixedDelay()` methods. +Task instances can also be submitted to a `CompletionStage` that is +backed by a `ManagedScheduledExecutorService`. Task instances will run as an extension of the Jakarta EE container instance that submitted the task and may interact with Jakarta EE resources as defined in other sections of this specification.