# Understanding Guava's AbstractFuture for Custom Asynchronous Computations

> Master Guava's AbstractFuture for custom async computations. Learn how this lock-free ListenableFuture implementation manages completion, cancellation, and listeners.

- Repository: [Google/guava](https://github.com/google/guava)
- Tags: deep-dive
- Published: 2026-08-08

---

**`AbstractFuture<V>` is Guava's low-level, lock-free implementation of `ListenableFuture` that provides a state machine for managing completion, cancellation, and listener notification, exposing protected hooks like `set()`, `setException()`, and `interruptTask()` for custom asynchronous logic.**

Custom asynchronous computations in Java require careful handling of state transitions, thread synchronization, and callback notification. In the `google/guava` library, `AbstractFuture` serves as the foundational building block for creating robust `ListenableFuture` implementations without managing complex concurrency primitives manually. This article explores the internal mechanisms of `AbstractFuture` and demonstrates how to leverage its extension points for building custom futures.

## Core State Machine and Lock-Free Design

The `AbstractFuture` class implements a sophisticated state machine centered around the volatile `valueField`, which atomically tracks the future's lifecycle from pending to completion.

### State Representation

In [`AbstractFutureState.java`](https://github.com/google/guava/blob/main/AbstractFutureState.java), the `valueField` can hold one of several distinct states defined in lines 71-80 and referenced throughout [`AbstractFuture.java`](https://github.com/google/guava/blob/main/AbstractFuture.java). These include:

- `null` – indicating the future has not yet completed
- `NULL` – a sentinel object representing a successful `null` result (lines 78-80 in [`AbstractFutureState.java`](https://github.com/google/guava/blob/main/AbstractFutureState.java))
- `Cancellation` – representing a cancelled future (lines 71-75 in [`AbstractFutureState.java`](https://github.com/google/guava/blob/main/AbstractFutureState.java))
- `Failure` – wrapping a throwable for failed futures (lines 51-66 in [`AbstractFuture.java`](https://github.com/google/guava/blob/main/AbstractFuture.java))
- `DelegatingToFuture` – an intermediate state created by `setFuture` (lines 203-215 in [`AbstractFuture.java`](https://github.com/google/guava/blob/main/AbstractFuture.java))

### Lock-Free Synchronization

All mutations to `valueField`, `listenersField`, and `waitersField` occur through Compare-And-Swap (CAS) operations provided by the `AtomicHelper` class. As implemented in [`AbstractFutureState.java`](https://github.com/google/guava/blob/main/AbstractFutureState.java) lines 41-68, the helper selects the most efficient atomic primitive available at runtime: **VarHandle** on Java 9+, falling back to **Unsafe**, then **AtomicReferenceFieldUpdater**, and finally synchronized blocks for older JVMs.

## Managing Listeners and Blocking Threads

`AbstractFuture` coordinates between non-blocking callbacks and blocking thread waits using two distinct Treiber stacks.

### Listener Execution Stack

Listeners registered via `addListener` are stored as a lock-free Treiber stack in `listenersField`. According to lines 62-89 in [`AbstractFuture.java`](https://github.com/google/guava/blob/main/AbstractFuture.java), `addListener` pushes a new `Listener` node unless the future is already complete, in which case the listener executes immediately. When completion occurs, the `complete` method (lines 445-508) unwinds this stack and executes each listener.

### Waiter Management for Blocking Gets

Threads calling `get()` form another Treiber stack in `waitersField`. The `blockingGet` implementation in [`AbstractFutureState.java`](https://github.com/google/guava/blob/main/AbstractFutureState.java) (lines 120-172) parks waiting threads using `LockSupport.parkNanos` and unparks them once the future completes, avoiding heavy kernel mutexes.

## Cancellation Propagation

When `cancel` succeeds, `AbstractFuture` propagates the cancellation to delegated futures if they implement the internal `Trusted` marker interface. This optimization appears in lines 604-616 of [`AbstractFuture.java`](https://github.com/google/guava/blob/main/AbstractFuture.java), ensuring that cancellation chains terminate quickly without unnecessary indirection.

## Extension Points for Custom Futures

Subclasses override only three protected methods to integrate custom logic while the core lock-free state machine remains untouched.

### Completing the Future

The `set(V value)` and `setException(Throwable throwable)` methods transition the future to a terminal state. These methods are thread-safe and may be called from any thread.

### Cancellation and Interruption

`interruptTask()` is invoked when `cancel(true)` succeeds, providing a hook to interrupt custom computation threads. The default implementation is empty.

### Post-Completion Hooks

`afterDone()` runs exactly once after the future reaches a terminal state, useful for lightweight cleanup or metrics collection without blocking the completion thread.

## Practical Implementation Examples

The following examples demonstrate patterns for extending `AbstractFuture` in `google/guava`.

### Delayed Completion with Scheduled Tasks

```java
class DelayedFuture<T> extends AbstractFuture<T> {
    private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();

    DelayedFuture(Callable<T> task, long delay, TimeUnit unit) {
        scheduler.schedule(() -> {
            try {
                T result = task.call();
                set(result);               // completes the future
            } catch (Exception e) {
                setException(e);           // marks the future as failed
            } finally {
                scheduler.shutdown();
            }
        }, delay, unit);
    }

    @Override protected void interruptTask() {
        // Interrupt the scheduler thread if possible.
        scheduler.shutdownNow();
    }
}

```

### Delegating to Another Future

```java
class TransformFuture<I, O> extends AbstractFuture<O> {
    TransformFuture(ListenableFuture<I> input, Function<? super I, ? extends O> fn, Executor exec) {
        setFuture(Futures.transformAsync(input,
            i -> Futures.immediateFuture(fn.apply(i)), exec));
    }
}

```

### Post-Completion Metrics

```java
class TimedFuture<T> extends AbstractFuture<T> {
    private final long startNanos = System.nanoTime();

    @Override protected void afterDone() {
        long elapsed = System.nanoTime() - startNanos;
        System.out.println("Future completed in " + TimeUnit.NANOSECONDS.toMillis(elapsed) + " ms");
    }
}

```

## Summary

- `AbstractFuture` provides a **lock-free state machine** for `ListenableFuture` implementations using CAS operations on volatile fields.
- **State transitions** are managed through `valueField`, supporting pending, success, failure, cancellation, and delegation states.
- **Listener and waiter stacks** use Treiber stack algorithms for non-blocking callback execution and efficient thread parking.
- **Extension points** (`set`, `setException`, `interruptTask`, `afterDone`) allow subclasses to implement custom asynchronous logic without managing synchronization.
- **Cancellation propagation** automatically delegates to `Trusted` futures to prevent resource leaks.

## Frequently Asked Questions

### When should I extend AbstractFuture instead of using Futures.transform?

Extend `AbstractFuture` when you need **low-level control** over completion timing, cancellation semantics, or resource cleanup that `Futures.transform` cannot provide. Use the utility methods in `Futures` for standard transformations like `transform`, `catching`, or `immediateFuture`, as they handle common patterns without boilerplate.

### How does AbstractFuture achieve lock-free synchronization?

`AbstractFuture` delegates atomic operations to `AtomicHelper` in [`AbstractFutureState.java`](https://github.com/google/guava/blob/main/AbstractFutureState.java), which selects the best available primitive at runtime—from **VarHandle** on modern JDKs down to **synchronized** blocks on legacy platforms. All state changes to `valueField`, `listenersField`, and `waitersField` occur through Compare-And-Swap operations rather than intrinsic locks.

### What is the difference between set() and setFuture()?

`set(V value)` immediately transitions the future to a completed state with the given value, while `setFuture(ListenableFuture<? extends V> future)` enters a `DelegatingToFuture` intermediate state that mirrors the result of the provided future. The latter propagates cancellation and completion automatically once the delegated future finishes, as seen in lines 203-215 of [`AbstractFuture.java`](https://github.com/google/guava/blob/main/AbstractFuture.java).

### How do I properly propagate cancellation in a custom AbstractFuture?

Override `interruptTask()` to halt your custom computation when `cancel(true)` is called, and ensure any delegated futures implement the `Trusted` interface for automatic propagation. The `AbstractFuture` implementation handles the state transition and listener notification; your subclass only needs to respond to the interruption signal.