Using CompletableFuture for Asynchronous Programming in Java: Examples and Best Practices

This article explains why asynchronous programming improves performance, compares serial and parallel implementations of a login flow, and demonstrates how to use Java's CompletableFuture API—including supplyAsync, runAsync, callbacks, composition, and error handling—to write efficient backend code.

Architect
Architect
Architect
Using CompletableFuture for Asynchronous Programming in Java: Examples and Best Practices

Most developers perform CRUD operations synchronously; this article shows how to use CompletableFuture to optimize project code and improve performance.

Why use asynchronous programming? In a login scenario, fetching role, menu, balance, and points sequentially takes 1 second (500 ms + 200 ms + 200 ms + 100 ms). Running these tasks in parallel reduces the total time to the longest single task (500 ms), effectively doubling throughput.

Serial implementation example:

@Test
public void login(Long userId) {
    log.info("开始查询用户全部信息---串行!");
    getUserRole(userId);
    getUserMenu(userId);
    getUserAmount(userId);
    getUserIntegral(userId);
    log.info("封装用户信息返回给前端!");
}

Asynchronous implementation with CompletableFuture:

@Test
public void asyncLogin() {
    long startTime = System.currentTimeMillis();
    log.info("开始查询用户角色信息!");
    CompletableFuture<Map<String, Object>> roleFuture = CompletableFuture.supplyAsync(() -> {
        Thread.sleep(500);
        Map<String, Object> map = new HashMap<>();
        map.put("role", "管理员");
        return map;
    });
    // similar futures for menu, amount, integral
    roleFuture.join();
    // join other futures
    log.info("查询用户全部信息总耗时:" + (System.currentTimeMillis() - startTime) + "毫秒");
}

Creating tasks: supplyAsync returns a value, while runAsync does not. Both can use the default ForkJoinPool or a custom ExecutorService.

Callback methods: thenRun / thenRunAsync execute a second task after the first without passing a result; thenAccept / thenAcceptAsync receive the previous result but return void; thenApply / thenApplyAsync transform the result and return a new value.

Example of thenRun:

CompletableFuture<Void> amountFuture = CompletableFuture.runAsync(() -> {
    // simulate work
});
CompletableFuture<Void> next = amountFuture.thenRun(() -> {
    // second task
});
next.get();

Combining multiple futures: thenCombine, thenAcceptBoth, and runAfterBoth wait for two futures to finish (AND logic). applyToEither, acceptEither, and runAfterEither proceed when any one finishes (OR logic). allOf completes when all supplied futures finish; anyOf completes when any finishes.

Error handling: exceptionally handles exceptions and provides a fallback value; whenComplete runs after completion without altering the result; handle can transform the result or recover from errors.

Common pitfalls: Calling Future.get() or join() is required to surface exceptions; get() blocks, so a timeout should be set. The default thread pool size equals CPU cores – 1, which may be insufficient for high‑load services; using a custom thread pool with an appropriate rejection policy (e.g., AbortPolicy) is recommended.

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.

BackendJavaconcurrencyAsynchronousCompletableFuture
Architect
Written by

Architect

Professional architect sharing high‑quality architecture insights. Topics include high‑availability, high‑performance, high‑stability architectures, big data, machine learning, Java, system and distributed architecture, AI, and practical large‑scale architecture case studies. Open to ideas‑driven architects who enjoy sharing and learning.

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.