
Java 21 introduces Structured Concurrency to simplify and organize concurrent programming. It’s part of Project Loom, designed to make managing multiple threads (especially Virtual Threads) more readable, reliable, and easier to cancel or handle as a group.
1. What Is Structured Concurrency?
✅ Structured concurrency treats multiple concurrent tasks as a single unit of work.
✅ It ensures that tasks start, run, and finish together within a scope.
✅ If one task fails, the entire group can be cancelled or handled cleanly.
🧠 Think of it like:
“If one thread in a group fails, cancel the rest, and wait for them all to finish together.“
2. Before Structured Concurrency: Manual Thread Management
🔴 Manual thread handling required:
- Creating a thread pool
- Tracking each task
- Manually shutting them down
- Handling exceptions independently
📌 Example (Before Java 21 – Manual & Messy)
ExecutorService executor = Executors.newFixedThreadPool(2);
Future<String> result1 = executor.submit(() -> fetchData1());
Future<String> result2 = executor.submit(() -> fetchData2());
String data1 = result1.get(); // Might block or throw
String data2 = result2.get();
executor.shutdown();
❌ No built-in way to cancel both if one fails.
3. Java 21+ Solution: StructuredTaskScope
✅ Java 21 introduces StructuredTaskScope
, a powerful way to:
- Run tasks in parallel
- Wait for all or any to complete
- Handle errors and timeouts as a group
4. Example: Run Two Tasks in Parallel and Wait for Both
📌 Using StructuredTaskScope.ShutdownOnFailure
import java.util.concurrent.StructuredTaskScope;
public class Main {
public static void main(String[] args) throws InterruptedException {
try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
StructuredTaskScope.Subtask<String> userTask = scope.fork(() -> fetchUser());
StructuredTaskScope.Subtask<String> ordersTask = scope.fork(() -> fetchOrders());
scope.join(); // Wait for both
scope.throwIfFailed(); // Propagate exceptions if any
String user = userTask.get();
String orders = ordersTask.get();
System.out.println("User: " + user);
System.out.println("Orders: " + orders);
}
}
static String fetchUser() throws InterruptedException {
Thread.sleep(500); // Simulate delay
return "Alice";
}
static String fetchOrders() throws InterruptedException {
Thread.sleep(800); // Simulate delay
return "Order#12345";
}
}
✅ Output:
User: Alice
Orders: Order#12345
✔ If either fetchUser()
or fetchOrders()
failed, the other would be automatically cancelled.
5. Variants of StructuredTaskScope
Class | Behavior |
---|---|
StructuredTaskScope.ShutdownOnFailure | ✅ Cancel all subtasks if any fails |
StructuredTaskScope.ShutdownOnSuccess | ✅ Stop all subtasks when one successfully completes |
StructuredTaskScope | Manual control (neutral behavior) |
6. Real-World Scenarios
🚀 Use Structured Concurrency when:
- You need to fetch data from multiple APIs simultaneously.
- You’re running parallel background jobs, but one failure should cancel the group.
- You want simple cancellation and error handling for Virtual Threads.
✅ Example: Use ShutdownOnSuccess
for First-Finished Strategy
try (var scope = new StructuredTaskScope.ShutdownOnSuccess<String>()) {
scope.fork(() -> searchDatabase());
scope.fork(() -> searchCache());
scope.join();
scope.throwIfFailed();
String result = scope.result(); // First successful result
System.out.println("Search Result: " + result);
}
7. Comparison: Before vs. After Structured Concurrency
Feature | Before Java 21 | Java 21+ (Structured Concurrency) |
---|---|---|
Manual thread lifecycle | ✅ Required | ❌ Handled automatically |
Task coordination | ❌ Error-prone | ✅ Built-in join() & throwIfFailed() |
Cancellation | ❌ Manual | ✅ Automatic with ShutdownOnFailure |
Virtual Thread support | ❌ Complex | ✅ Seamless integration |
Lesson Reflection
- How does
StructuredTaskScope
simplify managing multiple threads? - When would
ShutdownOnSuccess
be more useful thanShutdownOnFailure
? - Can you think of a real-world situation where structured concurrency would make code safer or easier to debug?
The next Java enhancement: Foreign Function & Memory API (FFM API) introduced in Java 22 😊🚀