Understanding Structured Concurrency (Java 21+)
1. Using StructuredTaskScope API
| Class | Use |
|---|---|
StructuredTaskScope | Generic base |
ShutdownOnFailure | Cancel siblings on first failure |
ShutdownOnSuccess | Cancel siblings on first success |
| AutoCloseable | Use in try-with-resources |
Example: Parallel fetch
try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
var user = scope.fork(() -> userSvc.find(id));
var orders = scope.fork(() -> orderSvc.list(id));
scope.join().throwIfFailed();
return new Profile(user.get(), orders.get());
}
2. Creating Scoped Tasks
| Method | Returns |
|---|---|
scope.fork(Callable) | Subtask handle |
handle.get() | Result after join |
handle.state() | RUNNING/SUCCESS/FAILED |
3. Handling Task Failures
| Approach | Effect |
|---|---|
| ShutdownOnFailure + throwIfFailed | Re-throws first error |
| Inspect handles | Iterate, check state |
| Custom scope | Override handleComplete |
4. Using ShutdownOnFailure Policy
| API | Use |
|---|---|
scope.join() | Wait for completion or shutdown |
scope.joinUntil(deadline) | Bounded wait |
throwIfFailed([fn]) | Throw if any subtask failed |
5. Using ShutdownOnSuccess Policy
| API | Use |
|---|---|
result() | First successful value |
| Use case | Race multiple replicas |
| Failure | Throws if all subtasks failed |
6. Understanding Scope Lifecycle
| Phase | Action |
|---|---|
| Create | try-with-resources |
| Fork | Spawn subtasks (must be on owner thread) |
| Join | Block for all or shutdown |
| Close | Auto via try-with-resources |
7. Propagating Errors and Cancellation
| Mechanism | Detail |
|---|---|
| Shutdown | Interrupts unfinished subtasks |
| Caller interrupt | Propagates to scope's subtasks |
| Re-throw | throwIfFailed wraps cause |
8. Combining with Virtual Threads
| Aspect | Detail |
|---|---|
| Default factory | StructuredTaskScope uses VTs |
| Custom factory | Pass to constructor |
| Result | Massively concurrent, structured |
9. Implementing Custom Task Scopes
| Override | Purpose |
|---|---|
handleComplete(Subtask) | Custom completion logic |
| Aggregation | Collect all results |
| Quorum | Wait for K of N successes |
Example: Collect-all scope
class CollectingScope<T> extends StructuredTaskScope<T> {
final List<T> results = Collections.synchronizedList(new ArrayList<>());
protected void handleComplete(Subtask<? extends T> s) {
if (s.state() == Subtask.State.SUCCESS) results.add(s.get());
}
}
10. Understanding Deadline Propagation
| API | Use |
|---|---|
joinUntil(Instant) | Hard deadline |
| Sub-scope | Inherit / shorten deadline |
| Timeout exception | TimeoutException on overrun |