Mastering Java Async: Future, Callable, CompletableFuture, and FutureTask Explained

This article explores four Java asynchronous programming approaches—Future with Callable, CompletableFuture, and FutureTask—detailing their principles, usage patterns, code examples, and how to retrieve results from thread pools, helping developers improve performance for tasks like aggregating order and fee summaries.

macrozheng
macrozheng
macrozheng
Mastering Java Async: Future, Callable, CompletableFuture, and FutureTask Explained

We have a business scenario similar to a report that gathers user order summaries, shipping fee summaries, and various transaction fee summaries, then displays them on a page. The data sources are independent, and fetching them sequentially is slow.

To speed up the page, we can fetch each summary in parallel using multiple threads and combine the results. In Java, asynchronous thread results are typically obtained with Future, Callable, CompletableFuture, and FutureTask classes.

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 and return result
                return 42;
            }
        });
        // Get asynchronous task result
        Integer result = future.get();
        System.out.println("异步任务的结果是" + result);
        executor.shutdown();
    }
}

The principle is to submit a task to a thread pool, which returns a Future object that can later retrieve the task's result.

Callable interface: A generic interface that defines a call() method to implement a task returning a result and possibly throwing an exception.

Future interface: Represents the result of an asynchronous computation, providing methods like get() that block until the computation completes and returns the result.

The Callable interface itself does not start a thread; it defines a task that must be submitted to an ExecutorService thread pool for execution.

In ExecutorService, you can use submit(Callable<T> task) to submit a Callable task, which returns a Future for result retrieval.

Steps to start a Callable task:

Create a Callable instance by implementing the call() method with the desired logic.

Create an ExecutorService thread pool using factory methods such as Executors.newFixedThreadPool(int) or Executors.newCachedThreadPool().

Submit the Callable instance to the thread pool via submit(Callable<T> task).

The thread pool executes the task asynchronously in a separate thread.

Obtain the result through the Future 's get() method, which blocks until the task completes.

Overall, Callable works by submitting a task to an ExecutorService, which manages its execution in a separate thread, allowing asynchronous processing.

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 and return result
            return 43;
        });
        // Get asynchronous task result
        Integer result = future.get();
        System.out.println("异步任务的结果:" + result);
    }
}
CompletableFuture

(introduced in Java 8) enables asynchronous programming and task composition based on the concepts of a “completable” future.

The core principles of CompletableFuture are:

Asynchronous execution: Methods like supplyAsync() and runAsync() submit tasks that run in separate threads without blocking the main thread.

Callback mechanism: Methods such as thenApply(), thenAccept(), and thenRun() register callbacks to handle results, completion actions, or exceptions.

Task composition: Methods like thenCombine(), thenCompose(), and thenAcceptBoth() allow combining multiple tasks and defining dependencies.

Exception handling: Methods like exceptionally() and handle() provide ways to process exceptions thrown during task execution.

Waiting for completion: Similar to Future, CompletableFuture offers a get() method, but it does not block the calling thread because the task runs asynchronously.

In summary, CompletableFuture leverages callbacks and asynchronous execution to simplify handling of async tasks, result processing, composition, 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 and return result
            return 44;
        });
        Thread thread = new Thread(futureTask);
        thread.start();
        // Get asynchronous task result
        Integer result = futureTask.get();
        System.out.println("异步任务的结果:" + result);
    }
}
FutureTask

is a concrete implementation of the Future interface that also implements Runnable, allowing it to be executed by a thread or an executor.

The principle of FutureTask can be summarized as:

Encapsulate task: Accepts a Callable or Runnable and wraps it as an asynchronous task.

Execute task: Implements Runnable, so it can be submitted to an Executor (typically an ExecutorService) for execution in a separate thread.

Get result: Through the Future interface's get() method, it waits for task completion and returns the result, blocking if necessary.

Cancel task: Provides cancel(boolean mayInterruptIfRunning) to attempt cancellation; if cancelled, subsequent get() throws CancellationException.

Overall, FutureTask wraps a callable or runnable into a cancellable asynchronous task and uses the Future interface to retrieve results or handle cancellation.

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.

CompletableFutureCallableFutureFutureTask
macrozheng
Written by

macrozheng

Dedicated to Java tech sharing and dissecting top open-source projects. Topics include Spring Boot, Spring Cloud, Docker, Kubernetes and more. Author’s GitHub project “mall” has 50K+ stars.

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.