diff --git a/api/src/main/java/jakarta/servlet/AsyncContext.java b/api/src/main/java/jakarta/servlet/AsyncContext.java index 2f9620040..043052efb 100644 --- a/api/src/main/java/jakarta/servlet/AsyncContext.java +++ b/api/src/main/java/jakarta/servlet/AsyncContext.java @@ -17,6 +17,8 @@ package jakarta.servlet; +import java.util.concurrent.Executor; + /** * Class representing the execution context for an asynchronous operation that was initiated on a ServletRequest. * @@ -36,9 +38,17 @@ * {@link #dispatch} methods, call {@link #complete}. * * + *

+ * An AsyncContext is an {@link Executor} that provides mutual exclusion between container managed threads for the same + * request. Specifically container managed threads are mutually excluded from simultaneous calls to + * {@link Servlet#service(ServletRequest, ServletResponse)}, + * {@link Filter#doFilter(ServletRequest, ServletResponse, FilterChain)}, {@link ReadListener#onDataAvailable()}, + * {@link WriteListener#onWritePossible()} and to execution of the {@link Runnable}s passed to + * {@link AsyncContext#execute(Runnable)}. + * * @since Servlet 3.0 */ -public interface AsyncContext { +public interface AsyncContext extends Executor { /** * The name of the request attribute under which the original request URI is made available to the target of a @@ -188,6 +198,11 @@ public interface AsyncContext { * within the same asynchronous cycle will result in an IllegalStateException. If startAsync is subsequently called on * the dispatched request, then any of the dispatch or {@link #complete} methods may be called. * + *

+ * Best practise is to call this method in a way that is mutually excluded from other threads active on the same + * request. This can be achieved by only calling the method from a container managed thread. A container may issue a + * warning if a non managed thread is used and future versions of the specification may prohibit such calls. + * * @throws IllegalStateException if one of the dispatch methods has been called and the startAsync method has not been * called during the resulting dispatch, or if {@link #complete} was called * @@ -218,6 +233,11 @@ public interface AsyncContext { *

* See {@link #dispatch()} for additional details, including error handling. * + *

+ * Best practise is to call this method in a way that is mutually excluded from other threads active on the same + * request. This can be achieved by only calling the method from a container managed thread. A container may issue a + * warning if a non managed thread is used and future versions of the specification may prohibit such calls. + * * @param path the path of the dispatch target, scoped to the ServletContext from which this AsyncContext was * initialized * @@ -252,6 +272,11 @@ public interface AsyncContext { *

* See {@link #dispatch()} for additional details, including error handling. * + *

+ * Best practise is to call this method in a way that is mutually excluded from other threads active on the same + * request. This can be achieved by only calling the method from a container managed thread. A container may issue a + * warning if a non managed thread is used and future versions of the specification may prohibit such calls. + * * @param context the ServletContext of the dispatch target * @param path the path of the dispatch target, scoped to the given ServletContext * @@ -277,6 +302,11 @@ public interface AsyncContext { * startAsync has returned to the container, then the call will not take effect (and any invocations of * {@link AsyncListener#onComplete(AsyncEvent)} will be delayed) until after the container-initiated dispatch has * returned to the container. + * + *

+ * Best practise is to call this method in a way that is mutually excluded from other threads active on the same + * request. This can be achieved by only calling the method from a container managed thread. A container may issue a + * warning if a non managed thread is used and future versions of the specification may prohibit such calls. */ public void complete(); @@ -284,10 +314,28 @@ public interface AsyncContext { * Causes the container to dispatch a thread, possibly from a managed thread pool, to run the specified * Runnable. The container may propagate appropriate contextual information to the Runnable. * + * @see #execute(Runnable) * @param run the asynchronous handler */ public void start(Runnable run); + /** + * Execute the passed {@link Runnable} mutually excluded from all other container managed threads for the same request. + * The execution may be done by the calling thread, which will momentarily be a container managed thread; or by another + * container managed thread, possibly from a managed thread pool. Since execution of the {@link Runnable} will exclude + * other container managed methods, this method is not intended for long-running tasks, nor ones that may block. + *

+ * If {@link AsyncContext#complete()} is called, or the request lifecycle completes via a dispatch prior to the runnable + * being run, then it will never be run. + *

+ * The container may propagate appropriate contextual information to the Runnable. + * + * @see #start(Runnable) + * @param run the asynchronous handler + */ + @Override + public void execute(Runnable run); + /** * Registers the given {@link AsyncListener} with the most recent asynchronous cycle that was started by a call to one * of the {@link ServletRequest#startAsync} methods. @@ -405,5 +453,4 @@ public interface AsyncContext { * @return the timeout in milliseconds */ public long getTimeout(); - }