ReviseAlgo Logo

Multithreading

Callable and Future

Submit tasks that return values or throw exceptions using Callable, and track results via Future.

Interview: Commonly tests how Callable differs from Runnable, how to handle execution exceptions, and Future.get() blocking behavior.

Last Updated: June 13, 2026 10 min read

While Runnable represents a void task that cannot return values or throw checked exceptions, Callable<V> returns a generic result and can throw exceptions. A Future<V> acts as a handle to retrieve this asynchronous result.

Core Idea

Callable is a task that returns a value. Future is a placeholder for that value while it is computed asynchronously.

Why It Matters

Allows running CPU-heavy calculations in parallel threads and fetching the results safely when needed.

Interview Lens

Focuses on the difference between Runnable and Callable, and handling ExecutionException inside Future.get().

Callable vs. Runnable

Let's compare the two interfaces:

  • Method Signature: Runnable defines void run(); Callable defines V call() throws Exception.
  • Exceptions: Callable can throw checked exceptions directly from the signature. Runnable must catch all checked exceptions locally.
  • Retrieval: Future.get() blocks the calling thread until the Callable finishes execution.

Code Walkthrough

This program demonstrates how to submit a Callable task to an ExecutorService and resolve the Future result.

import java.util.concurrent.*;

public class CallableDemo { public static void main(String[] args) { ExecutorService executor = Executors.newSingleThreadExecutor();

Callable task = () -> { Thread.sleep(1000); // Simulate heavy math return 42; };

System.out.println("Submitting task..."); Future future = executor.submit(task);

try { // Future.get() blocks until the value is ready Integer result = future.get(2, TimeUnit.SECONDS); System.out.println("Result received: " + result); } catch (TimeoutException e) { System.err.println("Task timed out!"); } catch (InterruptedException | ExecutionException e) { System.err.println("Execution failed: " + e.getCause()); } finally { executor.shutdown(); } } }

Interview-Relevant Information

Q: How does Future propagate exceptions thrown inside a Callable?
Answer: If a Callable throws an exception, it is caught by the execution framework. When you call future.get(), it throws a checked ExecutionException. You can query the root cause of the error using e.getCause().

Quick Checklist

What is the return type of Callable? How does future.get() block? What exception is thrown on failure? If yes, you understand Callable and Future.

Use Cases

Running parallel database queries and joining results to render dashboards.

Offloading complex file parses to parallel workers.

Common Mistakes

Calling future.get() immediately after submitting, which converts the asynchronous execution into synchronous blocking.

Using future.get() without specifying a timeout limit, risking permanent thread blocks.