Custom Implementation of CompletableFuture in Java
A Complete Step-by-Step Guide
Introduction
CompletableFuture in Java is a powerful tool for asynchronous programming.
It allows executing tasks in the background and processing results once they’re available — without blocking the main thread.
It’s part of the java.util.concurrent package and provides capabilities such as:
- Non-blocking asynchronous execution
 - Task chaining
 - Combining multiple futures
 
Building your own version helps you understand the core mechanics — how results are stored, how callbacks are triggered, and how chaining works.
Step 1 — Understand the Requirements
Before diving into code, let’s outline what our custom version needs to do.
A custom CompletableFuture must:
- Allow asynchronous task execution in a separate thread.
 - Store the result for later retrieval.
 - Support callbacks when computation completes.
 - Support chaining or combining tasks sequentially.
 
Step 2 — Create Basic Structure
We start by creating a class CustomCompletableFuture<T> that will:
- Store the result
 - Track completion status
 - Allow registering callbacks
 
Code:
import java.util.function.Consumer;
public class CustomCompletableFuture<T> {
    private T result;
    private boolean isDone = false;
    private Consumer<T> callback;
    // Completes the future and triggers any callback
    public synchronized void complete(T value) {
        if (!isDone) {
            result = value;
            isDone = true;
            notifyAll();
            if (callback != null) {
                callback.accept(result);
            }
        }
    }
    // Waits for the result if not yet available
    public synchronized T get() throws InterruptedException {
        while (!isDone) {
            wait();
        }
        return result;
    }
    // Registers a callback to be executed when result is ready
    public synchronized void thenAccept(Consumer<T> action) {
        if (isDone) {
            action.accept(result);
        } else {
            callback = action;
        }
    }
}
This class can store results, notify waiting threads, and execute callbacks when a task completes.
Step 3 — Implement Asynchronous Execution
We now add the ability to run tasks asynchronously.
To do that, we create a static method supplyAsync() that runs a task on a new thread.
Code:
public interface Task<U> {
    U get();
}
public static <U> CustomCompletableFuture<U> supplyAsync(Task<U> task) {
    CustomCompletableFuture<U> future = new CustomCompletableFuture<>();
    new Thread(() -> {
        U value = task.get();
        future.complete(value);
    }).start();
    return future;
}
Now, you can execute a task asynchronously and receive a future to track its result.
Step 4 — Test CustomCompletableFuture
Let’s test the implementation with a simple asynchronous task.
Code:
public class CompletableFutureTest {
    public static void main(String[] args) throws InterruptedException {
        CustomCompletableFuture<String> future = CustomCompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "Task Completed";
        });
        future.thenAccept(result -> System.out.println("Callback: " + result));
        System.out.println("Main thread is not blocked.");
        String result = future.get();
        System.out.println("Result: " + result);
    }
}
✅ Expected Output
Main thread is not blocked.
Callback: Task Completed
Result: Task Completed
Step 5 — Add Task Chaining Support
One of the main strengths of CompletableFuture is chaining tasks — executing one after another once the previous completes.
Let’s add that feature with a thenApply() method.
Code:
public <U> CustomCompletableFuture<U> thenApply(Task<U> nextTask) {
    CustomCompletableFuture<U> nextFuture = new CustomCompletableFuture<>();
    thenAccept(result -> {
        U nextResult = nextTask.get();
        nextFuture.complete(nextResult);
    });
    return nextFuture;
}
Now, you can run dependent asynchronous operations sequentially.
Step 6 — Test Task Chaining
Here’s a test for task chaining using our new thenApply() method.
Code:
public class CompletableFutureChainTest {
    public static void main(String[] args) throws InterruptedException {
        CustomCompletableFuture<Integer> future = CustomCompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return 10;
        });
        future
            .thenApply(() -> 20)
            .thenAccept(result -> System.out.println("Chained Result: " + result));
        System.out.println("Main thread continues...");
    }
}
✅ Expected Output
Main thread continues...
Chained Result: 20
Step 7 — Add Exception Handling (Optional)
We can further enhance this by adding exception handling to manage runtime errors in asynchronous tasks.
This could include methods like:
- exceptionally() to handle exceptions gracefully.
 - handle() to process results or errors.
 
However, for simplicity, this basic version focuses on the core logic of result handling, callbacks, and chaining.
Complete Code — Custom CompletableFuture Example
Here’s the entire working implementation you can copy and run:
import java.util.function.Consumer;
// Step 1 & 2 — Custom CompletableFuture Implementation
public class CustomCompletableFuture<T> {
    private T result;
    private boolean isDone = false;
    private Consumer<T> callback;
    public synchronized void complete(T value) {
        if (!isDone) {
            result = value;
            isDone = true;
            notifyAll();
            if (callback != null) {
                callback.accept(result);
            }
        }
    }
    public synchronized T get() throws InterruptedException {
        while (!isDone) {
            wait();
        }
        return result;
    }
    public synchronized void thenAccept(Consumer<T> action) {
        if (isDone) {
            action.accept(result);
        } else {
            callback = action;
        }
    }
    // Step 3 — Asynchronous Execution
    public interface Task<U> {
        U get();
    }
    public static <U> CustomCompletableFuture<U> supplyAsync(Task<U> task) {
        CustomCompletableFuture<U> future = new CustomCompletableFuture<>();
        new Thread(() -> {
            U value = task.get();
            future.complete(value);
        }).start();
        return future;
    }
    // Step 5 — Task Chaining
    public <U> CustomCompletableFuture<U> thenApply(Task<U> nextTask) {
        CustomCompletableFuture<U> nextFuture = new CustomCompletableFuture<>();
        thenAccept(result -> {
            U nextResult = nextTask.get();
            nextFuture.complete(nextResult);
        });
        return nextFuture;
    }
}
// Step 4 — Test Simple Future
class CompletableFutureTest {
    public static void main(String[] args) throws InterruptedException {
        CustomCompletableFuture<String> future = CustomCompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "Task Completed";
        });
        future.thenAccept(result -> System.out.println("Callback: " + result));
        System.out.println("Main thread is not blocked.");
        String result = future.get();
        System.out.println("Result: " + result);
    }
}
// Step 6 — Test Task Chaining
class CompletableFutureChainTest {
    public static void main(String[] args) throws InterruptedException {
        CustomCompletableFuture<Integer> future = CustomCompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return 10;
        });
        future
            .thenApply(() -> 20)
            .thenAccept(result -> System.out.println("Chained Result: " + result));
        System.out.println("Main thread continues...");
    }
}
Real-World Use Cases
Custom CompletableFuture can be useful in:
- Running background tasks without blocking the main thread
 - Chaining dependent asynchronous operations
 - Building lightweight reactive systems
 - rk or database calls in the background
 
Limitations
While educational, this version lacks:
- Advanced combinators like thenCombine(), allOf(), or anyOf().
 - Timeout handling and cancellation support.
 - Proper error propagation.
 
In real-world production, you should use Java’s built-in CompletableFuture, which provides all these features safely and efficiently.
Summary
- CompletableFuture helps manage asynchronous tasks elegantly.
 - Building a CustomCompletableFuture improves understanding of:
- Threads and synchronization
 - Result propagation
 - Callback mechanisms
 - Task chaining logic
 
 
This custom version lays the foundation for mastering asynchronous and reactive programming in Java.
Next Blog- Custom Implementation of LinkedBlockingQueue in Java
                                                
                                                                
                                                                
                                                                
                                                                
                                                                
                                                                
                                                                
                                                                
                                                                
                                                                
                                                                
                                                                
                                                                
                                                                
                                                                
                                                                
                                                                
                                                                
                                                                
                                                                
                                                                
                                                                
                                                                
                                                                
                                                                
                                                                
                                                                
                                                                
                                                                
                                                                
                                                                
                                                                
                                                                
                                                                
                                                                
                                                                
                                                                
                                                                
                                                                
                                                                
                                                                
                                                                
                                                                
                                                                
                                                                
                                                                
                                                                
                                                                
                                                                
                                                                
                                                                
                                                                
                                                                
                                                                
                                                                
                                                                
                                                                
                                                                
                                                                
                                                                
                                                                
                                                                
                                                                
                                                                
                                                                
                                                                
                                                                