Callable and Future
IntermediateCallable returns a result and can throw checked exceptions; Future represents the pending result of an async computation.
Overview
Runnable cannot return a value or throw checked exceptions. Callable<V> solves both — its call() method returns V and can throw Exception. When submitted to an ExecutorService, it returns a Future<V> which acts as a handle to the pending result. Future.get() blocks until the result is ready. invokeAll() and invokeAny() coordinate multiple Callables. FutureTask wraps a Callable and can be used directly as both a Runnable and a Future.
Callable and Future Basics
Callable<V> is a functional interface with a single call() method returning V. Submit it to an ExecutorService to get a Future<V>.
Future.get() blocks until the result is available or throws ExecutionException (wrapping any exception thrown by call()). Use get(timeout, unit) to avoid indefinite blocking.
import java.util.concurrent.*;
ExecutorService pool = Executors.newFixedThreadPool(4);
// Callable — returns a value
Callable<String> task = () -> {
Thread.sleep(500);
return "Result from thread: " + Thread.currentThread().getName();
};
Future<String> future = pool.submit(task);
// Do other work while task runs...
System.out.println("Task submitted, doing other work");
// Get result — blocks until ready
try {
String result = future.get(2, TimeUnit.SECONDS);
System.out.println(result);
} catch (TimeoutException e) {
future.cancel(true); // cancel if too slow
System.err.println("Task timed out");
} catch (ExecutionException e) {
System.err.println("Task threw: " + e.getCause());
} catch (CancellationException e) {
System.err.println("Task was cancelled");
}
pool.shutdown();invokeAll and invokeAny
invokeAll() submits a collection of Callables and returns a list of Futures (all completed). invokeAny() returns the result of the first successful Callable — cancels the rest.
Useful for scatter-gather patterns: fan out work to multiple threads and collect results.
List<Callable<Integer>> tasks = List.of(
() -> fetchFromDatabase(),
() -> fetchFromCache(),
() -> fetchFromApi()
);
// Wait for ALL to complete
List<Future<Integer>> futures = pool.invokeAll(tasks, 5, TimeUnit.SECONDS);
List<Integer> results = futures.stream()
.map(f -> {
try { return f.get(); }
catch (Exception e) { return -1; }
})
.collect(Collectors.toList());
// Get result of FIRST to succeed (fastest source wins)
try {
Integer fastest = pool.invokeAny(tasks, 3, TimeUnit.SECONDS);
System.out.println("Fastest result: " + fastest);
} catch (TimeoutException e) {
System.err.println("All tasks timed out");
} catch (ExecutionException e) {
System.err.println("All tasks failed");
}FutureTask
FutureTask<V> implements both Runnable and Future<V>. It wraps a Callable and can be submitted to an executor, passed to a Thread, or run directly. Useful when you need a Future-compatible task before you have an executor.
FutureTask can also be used for lazy, one-time initialisation — only the first call to run() executes the task; subsequent calls return the cached result.
// FutureTask — both Runnable and Future
Callable<String> heavyComputation = () -> {
Thread.sleep(1000);
return "computed result";
};
FutureTask<String> task = new FutureTask<>(heavyComputation);
// Submit to executor
pool.submit(task);
// OR run on a plain thread
new Thread(task).start();
// Get the result (blocks)
String result = task.get();
// Lazy initialisation with FutureTask
public class HeavyResourceHolder {
private final FutureTask<Resource> loader = new FutureTask<>(() -> {
return new Resource(); // expensive, runs only once
});
public Resource getResource() throws Exception {
loader.run(); // idempotent — second call is a no-op
return loader.get();
}
}Interactive Visualization
Key Points to Remember
- Callable<V> returns a value and can throw checked exceptions — Runnable cannot.
- Future.get() blocks; use get(timeout, unit) to avoid infinite blocking.
- ExecutionException wraps the exception thrown inside call() — always check getCause().
- invokeAll() waits for all; invokeAny() returns the first success and cancels the rest.
- FutureTask is both a Runnable and a Future — useful for lazy one-time initialisation.
Practice Callable and Future in the Playground
Run and modify code directly in your browser - no setup needed.
Interview Questions
Sign in to ask AriaWhat is the difference between Runnable and Callable?
What exception does Future.get() throw if the task threw an exception?
What is the difference between invokeAll() and invokeAny()?
How do you cancel a running Future?
What is FutureTask and when would you use it instead of submitting to an executor?
Ask Aria about Callable and Future
Your personal AI tutor — ask anything about this concept