JEP 453, Structured Concurrency (Preview), has been Integrated from the Targeted status for JDK 21. Formerly an incubating API, this initial preview incorporates enhancements in response to feedback from the previous two rounds of incubation: JEP 428, Structured Concurrency (Incubator), delivered in JDK 19; and JEP 437, Structured Concurrency (Second Incubator), delivered in JDK 20. The only significant change in the current proposal is that the StructuredTaskScope::fork(...)
method returns a [Subtask
] rather than a Future
. This is a preview feature.
Structured Concurrency in JDK 21 is aimed at simplifying concurrent programming by introducing an API for structured concurrency. This approach treats groups of related tasks running in different threads as a single unit of work, thus streamlining error handling and cancellation, improving reliability, and enhancing observability. Let’s see an example:
Response handle() throws ExecutionException, InterruptedException {
try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
Supplier<String> user = scope.fork(() -> findUser());
Supplier<Integer> order = scope.fork(() -> fetchOrder());
scope.join() // Join both subtasks
.throwIfFailed(); // ... and propagate errors
// Here, both subtasks have succeeded, so compose their results
return new Response(user.get(), order.get());
}
//...
}
This code creates a new StructuredTaskScope
and uses it to fork two subtasks: one that executes findUser()
and another that executes fetchOrder()
. Once both subtasks have been completed, it creates a new Response
using the results of both subtasks.
Structured concurrency is a preview API, disabled by default. To use the StructuredTaskScope
API, developers must enable preview APIs to compile this code, as shown in the following command:
javac --release 21 --enable-preview Main.java
The same flag is also required to run the program:
java --enable-preview Main
However, one can directly run this using the source code launcher. In that case, the command line would be:
java --source 21 --enable-preview Main.java
The jshell option is also available but requires enabling the preview feature as well:
jshell --enable-preview
In practice, most uses of StructuredTaskScope
will not utilize the StructuredTaskScope
class directly but instead use one of the two subclasses implementing shutdown policies. These subclasses, ShutdownOnFailure
and ShutdownOnSuccess
, support patterns that shut down the scope when the first subtask fails or succeeds, respectively.
Structured concurrency treats groups of related tasks running in different threads as a single unit of work. This approach streamlines error handling and cancellation, improves reliability, and enhances observability. The developers, Ron Pressler, consulting member of the technical staff at Oracle and technical lead for OpenJDK’s Project Loom, and Alan Bateman, an engineer in the Java Platform Group at Oracle, intend to eliminate common risks associated with concurrent programming, like thread leaks and cancellation delays, and to enhance the observability of concurrent code.
The new feature does not aim to replace any of the concurrency constructs in the java.util.concurrent
package, such as ExecutorService
and Future
. It also does not aim to define the definitive structured concurrency API for the Java Platform or a method for sharing streams of data among threads.
Current concurrent programming models, such as the ExecutorService
API, introduce complexity and risks due to their unrestricted patterns of concurrency. These models don't enforce or track relationships among tasks and subtasks, making the management and observability of concurrent tasks challenging.
The structured concurrency model proposes that task structure should reflect code structure. In single-threaded code, the execution always enforces a hierarchy of tasks and subtasks, with the lifetime of each subtask relative to the others governed by the syntactic block structure of the code.
The new StructuredTaskScope
provides a simpler and safer alternative to ExecutorService
. This API encapsulates a group of related tasks that should be completed together, with failure of any subtask leading to the cancellation of the remaining subtasks.
Further details of the changes, including code examples and a comprehensive discussion of the motivation behind this feature, are available on the OpenJDK website.
This new API is a significant step toward making concurrent programming easier, more reliable, and more observable. It is expected to be particularly beneficial for building maintainable, reliable, and observable server applications. Developers interested in a deep dive into structured concurrency and learning the backstory can listen to the InfoQ Podcast, a YouTube session by Ron Pressler and the Inside Java articles.