Java 23 finalizes Structured Concurrency. Parent-child task relationships. Automatic cancellation. Clean concurrent code without complexity.
JOptimize Team
Java 23 finalizes Structured Concurrency.
No more thread spaghetti. No more tasks running after parent dies. No more cancellation forgotten.
Parent spawns children. Children finish before parent. Automatic timeout. Automatic cancellation.
Current Java concurrency (ugly):
public void process() throws Exception { ExecutorService executor = Executors.newFixedThreadPool(3); Future<Result> task1 = executor.submit(() -> work1()); Future<Result> task2 = executor.submit(() -> work2()); Future<Result> task3 = executor.submit(() -> work3()); try { Result r1 = task1.get(5, TimeUnit.SECONDS); Result r2 = task2.get(5, TimeUnit.SECONDS); Result r3 = task3.get(5, TimeUnit.SECONDS); } catch (TimeoutException e) { // Hope tasks cancel? Nope, they keep running task1.cancel(true); task2.cancel(true); task3.cancel(true); } finally { executor.shutdown(); // May not actually shutdown executor.awaitTermination(1, TimeUnit.SECONDS); } }
Tasks may still be running after method exits. Cancellation unreliable. Timeout management complex.
public void process() throws Exception { try (var scope = new StructuredTaskScope.ShutdownOnFailure()) { // Parent spawns children Subtask<Result> task1 = scope.fork(() -> work1()); Subtask<Result> task2 = scope.fork(() -> work2()); Subtask<Result> task3 = scope.fork(() -> work3()); // Wait for all children with timeout scope.joinUntil(Instant.now().plus(Duration.ofSeconds(5))); // If here: all children completed successfully Result r1 = task1.get(); Result r2 = task2.get(); Result r3 = task3.get(); } // On exit: all children cancelled automatically }
Clean. Children guaranteed finished before parent exits. Automatic cancellation.
Parent Task
├─ Child 1 (work1)
├─ Child 2 (work2)
└─ Child 3 (work3)
Parent waits for all children.
Parent exits → children cancelled.
Child exception → siblings cancelled.
No orphaned tasks.
One failure = cancel all siblings:
try (var scope = new StructuredTaskScope.ShutdownOnFailure()) { var task1 = scope.fork(() -> apiCall1()); var task2 = scope.fork(() -> apiCall2()); var task3 = scope.fork(() -> apiCall3()); scope.joinUntil(deadline); // If any task failed, others cancelled }
Useful for all-or-nothing operations.
First success = cancel others:
try (var scope = new StructuredTaskScope.ShutdownOnSuccess<Integer>()) { // Try 3 mirrors of same data var t1 = scope.fork(() -> fetchFromServer1()); var t2 = scope.fork(() -> fetchFromServer2()); var t3 = scope.fork(() -> fetchFromServer3()); scope.joinUntil(deadline); // First success wins, others cancelled int result = scope.result(); }
Useful for failover and racing.
Define custom cancellation logic:
class MajorityPolicy<T> extends StructuredTaskScope<T> { @Override protected void handleComplete(Subtask<? extends T> subtask) { if (subtask.state() == Subtask.State.SUCCESS) { successCount++; } if (successCount > total / 2) { shutdown(); // Majority reached } } }
Old (messy):
public UserData loadUser(String id) throws Exception { ExecutorService exec = Executors.newFixedThreadPool(3); Future<UserProfile> profileFuture = exec.submit(() -> apiClient.getProfile(id)); Future<List<Order>> ordersFuture = exec.submit(() -> apiClient.getOrders(id)); Future<Preferences> prefsFuture = exec.submit(() -> apiClient.getPreferences(id)); try { UserProfile profile = profileFuture.get(2, TimeUnit.SECONDS); List<Order> orders = ordersFuture.get(2, TimeUnit.SECONDS); Preferences prefs = prefsFuture.get(2, TimeUnit.SECONDS); return new UserData(profile, orders, prefs); } catch (TimeoutException e) { profileFuture.cancel(true); ordersFuture.cancel(true); prefsFuture.cancel(true); throw new Exception("Timeout loading user data"); } finally { exec.shutdown(); } }
New (clean):
public UserData loadUser(String id) throws Exception { try (var scope = new StructuredTaskScope.ShutdownOnFailure()) { var profile = scope.fork(() -> apiClient.getProfile(id)); var orders = scope.fork(() -> apiClient.getOrders(id)); var prefs = scope.fork(() -> apiClient.getPreferences(id)); scope.joinUntil(Instant.now().plus(Duration.ofSeconds(2))); return new UserData(profile.get(), orders.get(), prefs.get()); } }
4 lines vs 30 lines. Automatic cancellation. No resource leaks.
Java 23: Production-ready.
Adopt gradually:
Structured Concurrency finalizes in Java 23.
Parent-child relationships explicit. Automatic cancellation. Clean code.
No more thread management nightmares.
Optimize with JOptimize PRO. Use code LINKEDIN40 for 40% OFF.
Master Spring Boot, security, and Java performance with hands-on courses.
JOptimize finds N+1 queries, EAGER collections, and 70+ other issues in your Java codebase — in under 30 seconds.