Applying CompletableFuture for Asynchronous Programming in Java: A ZhiZhi Store Detail Page Case Study

This article explains the limitations of Java Future, introduces CompletableFuture's asynchronous and compositional capabilities, and demonstrates how to refactor a store detail page service using CompletableFuture, custom thread pools, and design patterns to achieve parallel execution, reduced latency, and better code maintainability.

Zhuanzhuan Tech
Zhuanzhuan Tech
Zhuanzhuan Tech
Applying CompletableFuture for Asynchronous Programming in Java: A ZhiZhi Store Detail Page Case Study

1 Background

ZhiZhi store detail pages provide ordering and reservation functions on mini‑programs and apps. Initially the service handled low QPS with a simple serial implementation, but as the page grew richer the serial approach caused high latency (up to 5 seconds) and tight coupling.

Each module (basic product info, discount info, store info, inspection report, standard parameters, and assembly) takes 0.5–1 second. Executing them sequentially exceeds acceptable response times, while parallel execution could finish within about 2 seconds.

Java 8 introduced java.util.concurrent.CompletableFuture, extending Future and CompletionStage to support asynchronous multi‑threaded tasks.

2 Evolution of Future and CompletableFuture

2.1 Future Overview

The Future interface (in java.util.concurrent) provides three core abilities: cancel a running task, check if a task is done, and retrieve the task result.

package java.util.concurrent;<br/>public interface Future<V> {<br/>    // Cancel execution<br/>    boolean cancel(boolean mayInterruptIfRunning);<br/>    // Check cancellation status<br/>    boolean isCancelled();<br/>    // Check completion status<br/>    boolean isDone();<br/>    // Retrieve result (may block)<br/>    V get() throws InterruptedException, ExecutionException;<br/>    // Retrieve result with timeout<br/>    V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException;<br/>}

2.2 Limitations of Future

Blocking the main thread while waiting for results, leading to unnecessary CPU consumption.

No support for chaining dependent tasks.

Cannot combine results from multiple tasks.

Lacks built‑in exception handling.

These drawbacks motivated the introduction of CompletableFuture in JDK 8, which enables non‑blocking, chainable, and composable asynchronous programming.

3 CompletableFuture

CompletableFuture

implements Future and CompletionStage, offering functional‑style callbacks, result transformation, and task composition.

3.1 Capabilities

Besides the traditional get(), CompletableFuture provides:

3.1.1 Creating Asynchronous Tasks

public static CompletableFuture<Void> runAsync(Runnable runnable)<br/>public static CompletableFuture<Void> runAsync(Runnable runnable, Executor executor)<br/>public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier)<br/>public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier, Executor executor)
runAsync

creates a task without a return value, while supplyAsync creates one with a result, both defaulting to ForkJoinPool.commonPool() unless a custom executor is supplied.

3.1.2 Asynchronous Callbacks

// Called when the previous stage finishes, receives result or exception<br/>CompletableFuture<T> whenComplete(BiConsumer<? super T,? super Throwable> action)<br/>// Transforms result or exception and returns a new stage<br/><U> CompletableFuture<U> handle(BiFunction<? super T,Throwable,? extends U> fn)<br/>// Async version of whenComplete<br/>CompletableFuture<T> whenCompleteAsync(BiConsumer<? super T,? super Throwable> action)<br/>// Handles exception and provides an alternative result<br/>CompletableFuture<T> exceptionally(Function<Throwable,? extends T> fn)

3.1.3 Task Composition

The CompletionStage interface defines many composition methods; common ones include:

// Transform result asynchronously<br/><U> CompletableFuture<U> thenApplyAsync(Function<? super T,? extends U> fn)<br/>// Consume result without returning a value<br/>CompletableFuture<Void> thenAcceptAsync(Consumer<? super T> action, Executor executor)<br/>// Wait for all given futures to complete<br/>static CompletableFuture<Void> allOf(CompletableFuture<?>... cfs)<br/>// Complete when any future finishes<br/>static CompletableFuture<Object> anyOf(CompletableFuture<?>... cfs)

3.2 Solution for the Store Detail Page

The workflow is split into three phases:

Parallel retrieval of basic product info, inspection report, standard parameters, and store info.

Fetch discount info after phase 1 completes.

Assemble all results once phases 1 and 2 are done.

Implementation uses a custom thread pool and several CompletableFuture instances:

ExecutorService testThreadPool = Executors.newFixedThreadPool(10);<br/>ResultDTO resultDTO = new ResultDTO();<br/><br/>// Basic info<br/>CompletableFuture<Void> productBaseInfoFuture = CompletableFuture.runAsync(() -> {<br/>    BaseInfoDTO baseInfoDTO = rpcxx;<br/>    resultDTO.setBaseInfoDTO(baseInfoDTO);<br/>}, testThreadPool);<br/><br/>// Discount info (depends on basic info)<br/>CompletableFuture<Void> couponInfoFuture = productBaseInfoFuture.thenAcceptAsync(() -> {<br/>    CouponInfoDTO couponInfoDTO = rpcxx;<br/>    resultDTO.setCouponInfoDTO(couponInfoDTO);<br/>}, testThreadPool);<br/><br/>// Inspection report<br/>CompletableFuture<Void> qcInfoFuture = CompletableFuture.runAsync(() -> {<br/>    QcInfoDTO qcInfoDTO = rpcxx;<br/>    resultDTO.setQcInfoDTO(qcInfoDTO);<br/>}, testThreadPool);<br/><br/>// Store info<br/>CompletableFuture<Void> storeInfoFuture = CompletableFuture.runAsync(() -> {<br/>    StoreInfoDTO storeInfoDTO = rpcxx;<br/>    resultDTO.setStoreInfoDTO(storeInfoDTO);<br/>}, testThreadPool);<br/><br/>// Standard parameters<br/>CompletableFuture<Void> spuInfoFuture = CompletableFuture.runAsync(() -> {<br/>    SpuInfoDTO spuInfoDTO = rpcxx;<br/>    resultDTO.setSpuInfoDTO(spuInfoDTO);<br/>}, testThreadPool);<br/><br/>// Wait for all parallel tasks<br/>CompletableFuture<Void> allQuery = CompletableFuture.allOf(couponInfoFuture, qcInfoFuture, storeInfoFuture, spuInfoFuture);<br/>// Assemble final result<br/>CompletableFuture<Void> buildFuture = allQuery.thenAcceptAsync((r) -> {<br/>    // assembly logic here<br/>}, testThreadPool).join();

This approach reduces the overall latency to the longest individual module (≈1 second) and decouples the code.

3.3 Further Refactoring with Factory & Strategy

To avoid repetitive task definitions, each module can be represented as a strategy handler selected via a simple factory. All handlers are executed with CompletableFuture.allOf():

List<String> eventList = Arrays.asList("xx", "xxx");<br/>CompletableFuture.allOf(eventList.stream().map(event -><br/>    CompletableFuture.runAsync(() -> {<br/>        // obtain handler from factory based on event type<br/>        if (handler != null) { /* execute */ }<br/>    }, testThreadPool)<br/>).toArray(CompletableFuture[]::new)).join();

3.4 Actual Impact

After refactoring the ZhiZhi store detail API with CompletableFuture + Factory + Strategy, the code became loosely coupled, easier to extend, and showed a noticeable reduction in response time in production.

4 Summary

Use CompletableFuture when multiple independent tasks can run in parallel; the more tasks, the greater the benefit.

It supports both sequential chaining and combinatorial patterns (AND/OR).

When collecting results in a shared collection, ensure thread‑safety.

Handle task dependencies and timeouts to avoid blocking the system.

5 References

https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html

https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletionStage.html

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.

BackendJavaconcurrencyAsynchronousCompletableFuturethread pool
Zhuanzhuan Tech
Written by

Zhuanzhuan Tech

A platform for Zhuanzhuan R&D and industry peers to learn and exchange technology, regularly sharing frontline experience and cutting‑edge topics. We welcome practical discussions and sharing; contact waterystone with any questions.

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.