Choosing the Right Java Async Tool: Future, CompletableFuture, or FutureTask

This article compares three Java concurrency approaches—Future with Callable, CompletableFuture, and FutureTask—explaining their underlying principles, step‑by‑step usage, code examples, and trade‑offs so you can decide which asynchronous tool best fits your reporting workload.

Java Web Project
Java Web Project
Java Web Project
Choosing the Right Java Async Tool: Future, CompletableFuture, or FutureTask

Using Future and Callable

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<Integer> future = executor.submit(new Callable<Integer>() {
            public Integer call() throws Exception {
                // get various summaries, return result
                return 42;
            }
        });
        // get async task result
        Integer result = future.get();
        System.out.println("Async task result is " + result);
        executor.shutdown();
    }
}

The Callable interface defines a single call() method that can return a value and throw checked exceptions. A Future represents the pending result of an asynchronous computation and provides get(), which blocks until the computation finishes.

Step 1 – Create Callable instance: Implement call() with the business logic (e.g., aggregating order, shipping, and fee data) and return the computed value.

Step 2 – Create an ExecutorService thread pool: Use Executors.newSingleThreadExecutor() or other factory methods such as newFixedThreadPool(int nThreads) or newCachedThreadPool().

Step 3 – Submit the task: Call executor.submit(Callable<T> task), which returns a Future<T> linked to the submitted task.

Step 4 – Asynchronous execution: The thread pool runs the Callable in a separate thread, leaving the main thread free.

Step 5 – Retrieve the result: Invoke future.get(); if the task is not yet finished, the call blocks until the result is available.

This pattern decouples task definition from execution and allows the main thread to continue processing while the heavy aggregation runs in parallel.

Using CompletableFuture

import java.util.concurrent.CompletableFuture;

public class Main {
    public static void main(String[] args) throws InterruptedException, ExecutionException {
        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
            // get various summaries, return result
            return 43;
        });
        Integer result = future.get();
        System.out.println("Async task result: " + result);
    }
}
CompletableFuture

(introduced in Java 8) combines the concepts of a Future and a callback mechanism. It enables asynchronous execution via methods such as supplyAsync() or runAsync(), and provides a rich set of composition methods.

Asynchronous execution: supplyAsync() runs the supplied lambda in a separate thread, returning a CompletableFuture immediately.

Callback mechanism: Methods like thenApply(), thenAccept(), and thenRun() register functions that are invoked when the computation completes, allowing result processing, side‑effects, or further chaining.

Task composition: thenCombine(), thenCompose(), and thenAcceptBoth() let you combine multiple asynchronous tasks, expressing dependencies without blocking.

Exception handling: exceptionally() and handle() let you react to errors thrown during asynchronous execution.

Waiting for completion: get() is still available, but unlike the classic Future, it does not block the thread that initiated the async call because the work is already running independently.

Overall, CompletableFuture offers a non‑blocking, callback‑driven model that simplifies complex asynchronous workflows and error handling.

Using FutureTask

import java.util.concurrent.*;

public class Main {
    public static void main(String[] args) throws InterruptedException, ExecutionException {
        FutureTask<Integer> futureTask = new FutureTask<>(() -> {
            // get various summaries, return result
            return 44;
        });
        Thread thread = new Thread(futureTask);
        thread.start();
        Integer result = futureTask.get();
        System.out.println("Async task result: " + result);
    }
}
FutureTask

is a concrete implementation of both Future and Runnable. It wraps a Callable (or Runnable) into a cancellable asynchronous task.

Encapsulate the task: Pass a Callable or Runnable to the FutureTask constructor.

Execute the task: Because FutureTask implements Runnable, it can be submitted to an Executor or started directly in a new Thread.

Retrieve the result: The Future methods are available; calling futureTask.get() blocks until the computation finishes and returns the value.

Cancel the task: futureTask.cancel(boolean mayInterruptIfRunning) attempts to stop execution, causing a CancellationException on subsequent get() calls.

In practice, all four approaches— Future + Callable, CompletableFuture, FutureTask, and plain Future —can satisfy the requirement of aggregating independent data sources concurrently; the choice depends on the need for callbacks, composition, or simple blocking retrieval.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

javaconcurrencyThreadPoolCompletableFutureFutureFutureTask
Java Web Project
Written by

Java Web Project

Focused on Java backend technologies, trending internet tech, and the latest industry developments. The platform serves over 200,000 Java developers, inviting you to learn and exchange ideas together. Check the menu for Java learning resources.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.