Error Handling and Cancellation
Propagate failures cleanly.
Error Handling and Cancellation is a free Java Academy lesson on CoddyKit — lesson 4 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Java Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.
Failures in a Tree of Tasks
When subtasks run concurrently, errors can happen in any branch. Structured concurrency gives you a disciplined way to propagate those failures up to the parent.
This lesson covers exceptions, cancellation, interruption, and timeouts.
Where Exceptions Surface
A subtask that throws does not crash your program immediately. The exception is captured on its Subtask handle. Where it surfaces depends on the policy:
ShutdownOnFailure: atthrowIfFailed()ShutdownOnSuccess: atresult()if none succeeded
Propagating with throwIfFailed
Here a subtask fails. throwIfFailed() rethrows it wrapped in ExecutionException, which we catch in main.
import java.util.concurrent.*;
public class Main {
public static void main(String[] args) throws InterruptedException {
try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
scope.fork(() -> "ok");
scope.fork(() -> { throw new RuntimeException("boom"); });
scope.join();
scope.throwIfFailed();
System.out.println("never reached");
} catch (ExecutionException e) {
System.out.println("Caught cause: " + e.getCause().getMessage());
}
}
}Mapping to a Custom Exception
throwIfFailed accepts a function to wrap the cause in your own exception type, keeping your API clean.
import java.util.concurrent.StructuredTaskScope;
class DataAccessException extends Exception {
DataAccessException(Throwable cause) { super(cause); }
}
public class Main {
public static void main(String[] args) throws Exception {
try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
scope.fork(() -> { throw new RuntimeException("db down"); });
scope.join();
scope.throwIfFailed(DataAccessException::new);
} catch (DataAccessException e) {
System.out.println("Wrapped: " + e.getCause().getMessage());
}
}
}Automatic Cancellation
When one subtask fails under ShutdownOnFailure, the scope cancels the siblings by interrupting their threads. You do not write any cancellation code yourself.
This prevents wasted work and dangling tasks.
Interruption Is the Mechanism
Cancellation works by interrupting the subtask's virtual thread. Cooperative code should:
- Let blocking calls throw
InterruptedException - Periodically check
Thread.currentThread().isInterrupted()in long loops
Responding to Interruption
This task checks the interrupt flag in a loop so it can stop early when the scope shuts down.
public class Main {
public static void main(String[] args) throws InterruptedException {
Thread t = Thread.ofVirtual().start(() -> {
long count = 0;
while (!Thread.currentThread().isInterrupted()) {
count++;
if (count == 1_000_000) break;
}
System.out.println("Stopped after " + count + " iterations");
});
t.join();
}
}Deadlines with joinUntil
To bound total time, use joinUntil(Instant). If the deadline passes before all subtasks finish, it throws TimeoutException and the scope shuts the rest down.
Timeout Example Shape
A typical timeout-guarded fan-out looks like this. The deadline applies to the whole group, not each subtask individually.
import java.time.*;
import java.util.concurrent.*;
public class Main {
public static void main(String[] args) throws InterruptedException {
try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
scope.fork(() -> "fast");
scope.joinUntil(Instant.now().plus(Duration.ofSeconds(2)));
scope.throwIfFailed();
System.out.println("Completed within deadline");
} catch (TimeoutException e) {
System.out.println("Deadline exceeded");
} catch (ExecutionException e) {
System.out.println("A subtask failed");
}
}
}Always Re-check After join
The discipline is: after join() (or joinUntil), always call throwIfFailed() or read result() before trusting any subtask value. Skipping this can hide failures.
Clean Shutdown Guaranteed
No matter how a scope ends, normally, by failure, or by timeout, the closing of the try-with-resources block guarantees every subtask thread is finished. There are no leaks and no orphans.
Quick Check
Recall how sibling subtasks are stopped.
Recap
You learned error handling and cancellation:
- Exceptions surface at
throwIfFailed()orresult() - Map causes to custom exceptions via
throwIfFailed(mapper) - Cancellation works through thread interruption; write cooperative tasks
joinUntilenforces a group deadline- Scope close always cleans up
That completes the Structured Concurrency course.
Frequently asked questions
Is the “Error Handling and Cancellation” lesson free?
Yes — the full text of “Error Handling and Cancellation” is free to read here on the web, and the Java Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Java Academy course, upgrade to CoddyKit PRO.
What will I learn in “Error Handling and Cancellation”?
Propagate failures cleanly. You practise Java Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.
Do I need any experience to start Java Academy?
No prior experience is required. Java Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 4 of 4, so you can start here or from the beginning and move at your own pace.
How long does the “Error Handling and Cancellation” lesson take?
Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.
Can I write and run code in this Java Academy lesson?
Yes. Every Java Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.
All lessons in this course
- The Structured Concurrency Model
- StructuredTaskScope
- Shutdown on Failure and Success
- Error Handling and Cancellation