Structured concurrency (preview)

Java 21 Course · lesson 8 of 15 · 4 min read

Treat a group of concurrent subtasks as one unit that succeeds or fails together.

Open this lesson in the learning hub

Key points

  • Fire two Futures and one fails: the other keeps running, and nobody cancels it.
  • StructuredTaskScope ties subtask lifetimes to a block - leave the block, they are all done or cancelled.
  • ShutdownOnFailure cancels the siblings the moment one subtask throws.
  • It also fixes observability: the subtasks appear as children of the caller in a thread dump.
  • Preview in 21, so it needs --enable-preview and the API is still moving.

Example

// Preview API in Java 21 - requires --enable-preview to compile and run.
import java.util.concurrent.*;   // in 21 StructuredTaskScope lives here, not jdk.incubator

public class Main {
    record Weather(String city, int degrees) { }

    public static void main(String[] args) throws Exception {
        try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
            // fork() hands back a Subtask, not a Future - the scope owns the lifetime.
            StructuredTaskScope.Subtask<String>  user    = scope.fork(() -> "ada");
            StructuredTaskScope.Subtask<Weather> weather = scope.fork(() -> new Weather("London", 14));

            scope.join();             // wait for both
            scope.throwIfFailed();    // rethrow the first failure

            System.out.println(user.get() + " sees " + weather.get());
        }
        // Leaving the block guarantees no subtask is still running.
    }
}

Structured concurrency makes a group of subtasks behave like a block - they all end when it does.

This is a reading copy. The full lesson — with the visual explainer, the interactive lab and a Run button for the code — lives in the Java 21 Course course, and every lesson in it is listed on the Java 21 Course contents page.