Home/Learn/Java A–Z/Callable and Future

Callable and Future

Intermediate
Concurrency

Callable 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.

CallableFuture.java
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.

InvokeAllAny.java
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.java
// 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

NEWRUNNABLERUNNINGBLOCKEDWAITINGTERMINATED
synchronized(lock)— free
main
RUNNING
t1
NEW
t2
NEW
main thread creates Thread t1 and Thread t2. Both are in NEW state.
1 / 6

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 Aria
1

What is the difference between Runnable and Callable?

EasyTCS
2

What exception does Future.get() throw if the task threw an exception?

EasyAmazon
3

What is the difference between invokeAll() and invokeAny()?

MediumGoogle
4

How do you cancel a running Future?

MediumMicrosoft
5

What is FutureTask and when would you use it instead of submitting to an executor?

MediumOracle

Ask Aria about Callable and Future

Your personal AI tutor — ask anything about this concept