Java Separate a Task from Its Execution Policy
An executor manages how tasks are run. A Future represents an eventual result and lets the caller observe completion or failure.
Understand the idea
Submitting a Callable returns a Future whose get operation waits for the task’s result and can report a wrapped task failure. The executor also needs a lifecycle policy so worker threads do not outlive the application accidentally. In this course’s Java 21 baseline, ExecutorService is AutoCloseable, allowing a small scoped example. A production service often owns a longer-lived executor and closes it at a broader boundary.
Run it locally
Use a local JDK 21 or newer. Save the complete example as Main.java in a separate lab folder, then compile and run it with the commands below. Java examples do not run in Bhylu’s browser playground. The -ea option enables assertion checks used by some lessons.
javac --release 21 -encoding UTF-8 -d out Main.java
java -ea -cp out MainA worked example
import java.util.concurrent.*;
public class Main {
public static void main(String[] args) throws Exception {
try (ExecutorService executor = Executors.newFixedThreadPool(2)) {
Future<Integer> first = executor.submit(() -> 4 * 3);
Future<Integer> second = executor.submit(() -> 5 * 2);
System.out.println(first.get() + second.get());
}
}
}
Expected output
22The two tasks return independent integer results, and the caller combines them after get has obtained each result. The code does not assume which worker runs first. Closing the executor at the end makes its lifetime visible. get can block, so a real request boundary may need timeouts and cancellation rather than an indefinite wait.
Check the official Java documentation for detailed contracts and supported options.