Using Future, Callable, CompletableFuture, and FutureTask for Asynchronous Tasks in Java
This article explains how to improve backend performance by fetching independent report data concurrently using Java's Future, Callable, CompletableFuture, and FutureTask classes, provides code examples for each approach, and compares their principles, usage patterns, and cancellation capabilities.
In a typical reporting scenario where order, shipping, and fee data are fetched separately, sequential calls can cause noticeable page latency; using multithreading to retrieve each summary concurrently can dramatically improve response time.
Future and Callable
The Future and Callable interfaces allow tasks that return a result to be submitted to an ExecutorService . The Future object’s get() method blocks until the computation finishes.
package com.luke.designpatterns.demo;
import java.util.concurrent.*;
public class demo {
public static void main(String[] args) throws InterruptedException, ExecutionException {
ExecutorService executor = Executors.newSingleThreadExecutor();
Future
future = executor.submit(new Callable
() {
public Integer call() throws Exception {
// fetch various summaries
return 42;
}
});
// retrieve async result
Integer result = future.get();
System.out.println("异步任务的结果是" + result);
executor.shutdown();
}
}The Callable interface defines a single call() method that returns a value and may throw an exception, while Future provides methods such as get() , isDone() , and cancel() to manage the asynchronous computation.
CompletableFuture
CompletableFuture (introduced in Java 8) extends the Future model with a fluent API for callbacks, composition, and exception handling. Tasks are submitted via supplyAsync() or runAsync() , and the result can be processed with methods like thenApply() , thenAccept() , thenCombine() , etc.
import java.util.concurrent.CompletableFuture;
public class Main {
public static void main(String[] args) throws InterruptedException, ExecutionException {
CompletableFuture
future = CompletableFuture.supplyAsync(() -> {
// fetch various summaries
return 43;
});
// retrieve async result
Integer result = future.get();
System.out.println("异步任务的结果:" + result);
}
}The class supports non‑blocking composition, asynchronous callbacks, and convenient error handling via exceptionally() or handle() .
FutureTask
FutureTask implements both Runnable and Future , allowing a Callable or Runnable to be wrapped as a cancellable asynchronous task that can be executed by a thread or an executor.
import java.util.concurrent.*;
public class Main {
public static void main(String[] args) throws InterruptedException, ExecutionException {
FutureTask
futureTask = new FutureTask<>(() -> {
// fetch various summaries
return 44;
});
Thread thread = new Thread(futureTask);
thread.start();
// retrieve async result
Integer result = futureTask.get();
System.out.println("异步任务的结果:" + result);
}
}It can be cancelled via cancel(boolean) , and the result is obtained through the standard Future.get() method.
All three approaches achieve the same goal—parallelizing independent data‑fetching operations—but differ in flexibility, composability, and ease of handling callbacks and errors. Choose Future/Callable for simple one‑off tasks, CompletableFuture for complex pipelines, and FutureTask when you need a runnable that also returns a result.
Architecture Digest
Focusing on Java backend development, covering application architecture from top-tier internet companies (high availability, high performance, high stability), big data, machine learning, Java architecture, and other popular fields.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.