Java Callable and Future
Fast recall
Quick revision
Core answer
Whether you understand Callable as a value-returning task (vs Runnable's void) and Future as the handle to retrieve that value (get, cancel, isDone).
Using Runnable where you need a return value, or calling future.get() immediately and blocking the caller unnecessarily.
Callable returns a value (V) and can throw checked exceptions (vs Runnable's void); submit to an ExecutorService to get a Future; get() blocks, isDone() checks, cancel() cancels.
Interview-ready guide
Interview answer
Callable is a task that returns a value and can throw checked exceptions, which is the key difference from Runnable, whose run method returns void and can't propagate checked exceptions.
You submit a Callable to an ExecutorService, which returns a Future — a handle representing the pending result. The Future lets you call get to block until the result is ready, get with a timeout to block with a deadline, cancel true to interrupt the task, or isDone and isCancelled to check without blocking.
Callable is for tasks that compute a value — fetching a price, parsing a file, running a query — and Future is how you retrieve that value, often after waiting. The common mistakes are calling get immediately and blocking the caller thread, which defeats the concurrency benefit, using Runnable where a return value is needed, and not calling pool dot shutdown, which leaks threads.
Java Callable and Future
Direct Answer
Callable<V> is a task that returns a value (V) and can throw a checked exception — unlike Runnable, which returns void and can't propagate checked exceptions. You submit a Callable to an ExecutorService, which returns a Future<V> — a handle representing the pending result. You call future.get() to block until the result is ready, cancel() to cancel the task, or isDone() to check without blocking. Callable is for tasks that compute a value (fetch a price, parse a file); Future is how you retrieve that value, possibly after waiting.
Code Example
import java.util.concurrent.*;
// (1) Callable returns a value; Runnable does not.
Callable<Integer> task = () -> {
Thread.sleep(1000);
return 42; // returns Integer, can throw checked exc
};
// (2) Submit to an ExecutorService -> get a Future.
ExecutorService pool = Executors.newFixedThreadPool(2);
Future<Integer> future = pool.submit(task);
// (3) Retrieve the result. get() BLOCKS until ready.
while (!future.isDone()) { /* do other work, don't block yet */ }
Integer result = future.get(); // blocks here if not already done
System.out.println(result); // 42
future.cancel(true); // cancel a still-running task (interrupt)
pool.shutdown();
Common Mistakes & Pitfalls
- Calling future.get() immediately and blocking the caller thread, losing the concurrency benefit.
- Using Runnable where a return value is needed — Runnable can't return one.
- Not calling pool.shutdown(), leaking threads; or not handling get()'s checked exceptions.
Check your understanding
Answer these without looking back at the article.
- What is the difference between Callable and Runnable (return value, exceptions)?
- What is a Future, and how do you get one (submit to ExecutorService)?
- What does Future.get() do, and why not call it immediately if you can do other work?
- How do you cancel a running task, and check if it's done (cancel, isDone)?
Looking for a structured roadmap?
Every module on this page is also part of the full Java backend interview track.