Unlocking Java’s FutureTask: A Deep Dive into Asynchronous Programming

This article explains how to use JDK’s Future and FutureTask for asynchronous computation, walks through their APIs, internal state machine, core methods like run(), get(), cancel(), and highlights their limitations while introducing CompletableFuture as a more powerful alternative.

Programmer DD
Programmer DD
Programmer DD
Unlocking Java’s FutureTask: A Deep Dive into Asynchronous Programming

1. Introduction

This section explains how to use JDK's Future and FutureTask for asynchronous programming, covering the Future interface methods, the internal state machine of FutureTask, and the core methods run(), get(), and cancel(). It also discusses the limitations of FutureTask and introduces CompletableFuture as a more flexible solution.

2. JDK Future Overview

In the Java concurrency package (java.util.concurrent), Future represents the result of an asynchronous computation. It provides methods to check if the computation is complete, wait for completion, retrieve the result, and cancel the task. If the task is not finished, get() blocks the calling thread. If the task is cancelled, a CancellationException is thrown; if the thread is interrupted, an InterruptedException is thrown; if the computation throws an exception, an ExecutionException is thrown.

The Future interface diagram (Figure 3‑1‑1) shows five key methods: V get() throws InterruptedException, ExecutionException: Waits for the task to finish and returns the result; blocks if the task is not yet complete.

V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException

: Same as get() but with a timeout; throws TimeoutException if the timeout expires. boolean isDone(): Returns true if the task has completed (normally, exceptionally, or cancelled). boolean cancel(boolean mayInterruptIfRunning): Attempts to cancel the task; if mayInterruptIfRunning is true, the executing thread is interrupted. boolean isCancelled(): Returns true if the task was cancelled.

3. FutureTask Implementation

3.1 FutureTask Overview

FutureTask

implements Future and Runnable, allowing it to be submitted to a thread or thread pool. It can be constructed with a Callable (which returns a value) or with a Runnable plus a predefined result.

public class AsyncFutureExample {
    public static String doSomethingA() { ... }
    public static String doSomethingB() { ... }
    public static void main(String[] args) throws InterruptedException, ExecutionException {
        long start = System.currentTimeMillis();
        FutureTask<String> futureTask = new FutureTask<>(() -> {
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) { e.printStackTrace(); }
            System.out.println("--- doSomethingA---");
            return "TaskAResult";
        });
        Thread thread = new Thread(futureTask, "threadA");
        thread.start();
        String taskBResult = doSomethingB();
        String taskAResult = futureTask.get();
        System.out.println(taskAResult + " " + taskBResult);
        System.out.println(System.currentTimeMillis() - start);
    }
}

The example shows how to create a FutureTask, start it in a separate thread, run another task concurrently, and then wait for the result with get().

3.2 FutureTask State Machine

FutureTask

uses a volatile int state field to track its lifecycle. The possible states are: NEW = 0: Task created but not started. COMPLETING = 1: Result is being set. NORMAL = 2: Completed normally. EXCEPTIONAL = 3: Completed with an exception. CANCELLED = 4: Cancelled before it started. INTERRUPTING = 5: Cancellation in progress with interruption. INTERRUPTED = 6: Cancellation completed with interruption.

The state transitions are: NEW → COMPLETING → NORMAL: Normal completion. NEW → COMPLETING → EXCEPTIONAL: Exception during execution. NEW → CANCELLED: Cancelled before start. NEW → INTERRUPTING → INTERRUPTED: Cancelled while running with interruption.

Only the four terminal states ( NORMAL, EXCEPTIONAL, CANCELLED, INTERRUPTED) are final.

3.3 run() Method

The run() method is the execution body of the task. It first attempts to set the current thread as the runner using a CAS operation; if it fails or the task is not in NEW state, it returns immediately. If the task is still NEW, it invokes the underlying Callable. On successful execution, it records the result and transitions the state to NORMAL. If an exception occurs, it records the exception and transitions to EXCEPTIONAL. Finally, it clears the runner reference, handles possible cancellation interruption, and wakes up any threads waiting on the result.

3.4 set() and setException()

set(V v)

attempts a CAS from NEW to COMPLETING, stores the result in outcome, then sets the final state to NORMAL and calls finishCompletion() to wake waiting threads. setException(Throwable t) similarly CASes from NEW to COMPLETING, stores the exception in outcome, sets the final state to EXCEPTIONAL, and wakes waiting threads.

3.5 get() Method

get()

checks the current state; if the task is not yet completed (state ≤ COMPLETING), it calls awaitDone(false, 0L) to block until completion. Once finished, it calls report(s) to return the result or throw the appropriate exception.

awaitDone(boolean timed, long nanos)

This method loops, checking for interruption, task completion, or timeout. If the thread is interrupted, it removes its wait node and throws InterruptedException. If the task reaches a terminal state, it returns the state. Otherwise, it creates a WaitNode for the current thread (if not already queued) and parks the thread using LockSupport.park() (or parkNanos when timed).

3.6 cancel(boolean mayInterruptIfRunning)

The cancel method first attempts a CAS from NEW to either INTERRUPTING (if mayInterruptIfRunning is true) or CANCELLED. If the CAS fails, cancellation fails and false is returned. If successful and interruption is requested, the method retrieves the runner thread and calls interrupt(), then sets the final state to INTERRUPTED. Finally, it calls finishCompletion() to wake any waiting threads.

3.7 Limitations of FutureTask

While FutureTask provides basic asynchronous control, it has several drawbacks:

It cannot compose multiple asynchronous tasks into a single logical unit.

It lacks reactive callbacks; callers must block with get() to obtain results.

Users cannot manually complete a FutureTask; only the internal task can set the result.

Coordinating multiple futures (e.g., waiting for all to complete) requires additional boilerplate.

To address these issues, Java 8 introduced CompletableFuture, which allows explicit completion, chaining, and reactive composition.

4. Summary

The book "Java Asynchronous Programming in Practice" systematically covers common asynchronous scenarios in Java, including intra‑JVM async, remote procedure calls, web request async handling, and the internals of popular async frameworks. It also compares Java’s async mechanisms with Go’s built‑in concurrency model.

5. Giveaway

Thanks to Mechanical Industry Press for sponsoring a giveaway of five copies of the book. To participate, comment with an async‑related problem you face at work. The five comments with the most likes will each receive a copy of the new book. The deadline is January 11, 2020, 20:00.

FutureTask diagram
FutureTask diagram
FutureTask class diagram
FutureTask class diagram
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.

JavaAsynchronousCompletableFutureJDKFutureTask
Programmer DD
Written by

Programmer DD

A tinkering programmer and author of "Spring Cloud Microservices in Action"

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.