Callable and Future

Multithreading · lesson 10 of 38 · 3 min read

Get results and exceptions back out of background work using Callable and Future.

Open this lesson in the learning hub

Key points

  • Runnable returns nothing and cannot throw checked exceptions. Callable<V> returns a value and can throw.
  • submit() hands back a Future<V>, a receipt you redeem later.
  • get() blocks until the result exists. Prefer get(timeout, unit) so one stuck task cannot freeze the caller.
  • If the task threw, get() raises ExecutionException. The real error is in getCause().
  • invokeAll runs a batch and returns once all are done. invokeAny returns the first success and cancels the rest.
  • Futures cannot be chained or combined. When you need that, move up to CompletableFuture.

Example

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
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;

public class Main {
    public static void main(String[] args) throws Exception {
        ExecutorService pool = Executors.newFixedThreadPool(3);

        Future<Integer> answer = pool.submit(() -> { Thread.sleep(50); return 21 * 2; });
        System.out.println("ready yet? " + answer.isDone());
        System.out.println("answer   : " + answer.get());     // blocks until the value exists

        List<Callable<String>> jobs = new ArrayList<>();
        for (int i = 1; i <= 3; i++) { int n = i; jobs.add(() -> "result-" + n); }
        for (Future<String> f : pool.invokeAll(jobs)) {       // returns when all are done
            System.out.println("invokeAll: " + f.get());
        }

        Callable<Integer> failing = () -> { throw new IllegalStateException("db down"); };
        try {
            pool.submit(failing).get();
        } catch (ExecutionException e) {
            System.out.println("failed   : " + e.getCause().getMessage());  // unwrap the real cause
        }

        pool.shutdown();
        pool.awaitTermination(5, TimeUnit.SECONDS);
    }
}

A Future is a receipt. get() redeems it, and blocks until it can.

This is a reading copy. The full lesson — with the visual explainer, the interactive lab and a Run button for the code — lives in the Multithreading course, and every lesson in it is listed on the Multithreading contents page.