Callable and Future in Java
Callable<V> is a task that returns a result of type V and may throw a checked exception. When you submit a Callable to an executor, you immediately get back a Future<V>: a placeholder for a result that isn't ready yet. Later you call future.get(), which waits if necessary and then returns the result, or throws an ExecutionException if the task failed. In this lesson, you will learn how to use Callable and Future, including timeouts and cancellation.
Declaration
@FunctionalInterface
public interface Callable<V> {
V call() throws Exception;
}Methods of Future
| Method | Description |
|---|---|
V get() | It is used to wait for the task and return its result. |
V get(long timeout, TimeUnit unit) | It waits at most the given time, then throws TimeoutException. |
boolean isDone() | It returns true once the task has finished in any way. |
boolean cancel(boolean mayInterrupt) | It tries to cancel the task. |
boolean isCancelled() | It returns true if the task was canceled. |
State state() / resultNow() | It returns the state, or the result of a completed task (Java 19). |
Example: Computing Results in Parallel
Let's see an example that totals the marks of three students in parallel and collects the results.
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class CallableDemo {
public static void main(String[] args) throws Exception {
Map<String, int[]> marks = Map.of(
"Navika", new int[] {91, 88, 95},
"Srihitha", new int[] {78, 82, 80},
"Advitha", new int[] {85, 90, 87});
try (ExecutorService pool = Executors.newFixedThreadPool(3)) {
List<String> names = List.of("Navika", "Srihitha", "Advitha");
List<Future<Integer>> futures = new ArrayList<>();
for (String name : names) {
Callable<Integer> total = () -> {
int sum = 0;
for (int m : marks.get(name)) sum += m;
return sum;
};
futures.add(pool.submit(total));
}
for (int i = 0; i < names.size(); i++) {
System.out.println(names.get(i) + ": " + futures.get(i).get());
}
}
}
}Navika: 274
Srihitha: 240
Advitha: 262Explanation: Each Callable returns an Integer. submit returns a Future<Integer> at once, while the totals are computed on pool threads. get() waits for each result in turn. Because the futures are kept in the same order as the names, the output is in a fixed order no matter which task finished first.
Example: Failures, Timeouts and Cancellation
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
public class FutureProblems {
public static void main(String[] args) throws InterruptedException {
try (ExecutorService pool = Executors.newFixedThreadPool(2)) {
Future<Integer> failing = pool.submit(() -> Integer.parseInt("9l"));
try {
failing.get();
} catch (ExecutionException e) {
System.out.println("Task failed: " + e.getCause());
}
Future<String> slow = pool.submit(() -> {
Thread.sleep(5000);
return "late result";
});
try {
slow.get(200, TimeUnit.MILLISECONDS);
} catch (TimeoutException e) {
System.out.println("Gave up waiting after 200 ms");
} catch (ExecutionException e) {
System.out.println("Unexpected: " + e.getCause());
}
System.out.println("Canceled: " + slow.cancel(true)
+ ", state: " + slow.state());
}
}
}Task failed: java.lang.NumberFormatException: For input string: "9l"
Gave up waiting after 200 ms
Canceled: true, state: CANCELLEDExplanation: The first task throws NumberFormatException; get() wraps it in an ExecutionException, and getCause() reveals the original. The second task is too slow, so get with a timeout throws TimeoutException. cancel(true) interrupts the sleeping task, and its state becomes CANCELLED (the enum constant uses the British spelling).
Common Mistakes
Calling get() right after each submit. The tasks then run one at a time; submit all first, then call get.
Calling get() without a timeout on a task that might hang. Your thread may wait forever.
Ignoring the Future. Errors in the task are silently lost.
Interview Corner
What are Callable and Future?
Callable<V> is a functional interface whose call() method returns a value and may throw a checked exception. Submitting it to an ExecutorService returns a Future<V>, which represents the pending result: get() blocks until the task completes and returns the value, throws ExecutionException wrapping any exception from the task, or TimeoutException with a timed get; cancel attempts to stop the task, and isDone/isCancelled report its status.
Practice
- Easy: Submit a
Callablethat returns the length of "Anamaneni" and print the result from theFuture. - Harder: Submit five
Callabletasks with random sleeps, then useinvokeAnyto print the result of whichever finishes first.
Key Takeaways
Was this tutorial helpful?