Executors, futures, and cancellation
Bounded execution, result ordering, task failure, and cooperative cleanup
Separate a task from its execution policy
Callable describes a result-producing operation that may throw. ExecutorService owns worker scheduling, while Future represents completion, failure, or cancellation of one submission. Future.get blocks and wraps a task failure in ExecutionException; inspect its cause rather than losing the original exception. Submission order, start order, completion order, and result order are distinct choices.
ExecutorService executor = Executors.newFixedThreadPool(2);
try {
Future<Integer> result = executor.submit(() -> 7);
assert result.get() == 7;
} finally {
executor.shutdownNow();
}That fragment shows the lifecycle boundary, not complete production cleanup. A fixed thread pool limits active workers but its default queue is unbounded; a sustained producer can still exhaust memory. A bounded ThreadPoolExecutor queue needs a rejection/backpressure policy. CompletionService is useful for completion-order consumption; iterating Future.get in input order deliberately lets an earlier slow task delay later observed results.
Cancellation is a request
cancel(true) requests interruption of running work; the task must cooperate. shutdown rejects new submissions, while shutdownNow also attempts interruption and returns queued work that did not start. Neither alone proves all workers have terminated; awaitTermination checks that lifecycle. Preserve interruption when translating a failure, and cancel sibling work when the batch contract promises all-or-failure behavior.
Do not block a worker waiting for dependent work submitted to the same exhausted pool, which can deadlock even without locks. CompletableFuture composes dependent completions but does not erase those execution and cancellation questions; specify executors for blocking stages. Java 21 adds virtual threads as a later feature that reduces the cost of blocking threads. Virtual threads do not make CPU work cheaper or remove the need to bound downstream resources. These exercises stay compatible with Java 17.
Put it into practice
Implement the exercise in a full-screen workspace, then run its tests.