Optimizing Multiple Interface Calls with Asynchronous Execution in Java

To reduce response time when invoking multiple independent APIs, this article demonstrates how to refactor sequential Java calls into asynchronous executions using thread pools and CompletableFuture, providing complete code examples and performance comparisons.

Selected Java Interview Questions
Selected Java Interview Questions
Selected Java Interview Questions
Optimizing Multiple Interface Calls with Asynchronous Execution in Java

As business logic grows and data volumes increase, some interfaces become slow, prompting the need for performance optimization. This article introduces an asynchronous approach to call multiple independent interfaces in parallel, thereby reducing overall response time.

Applicable Conditions

Multiple independent interfaces with no mutual dependencies.

The longest‑running interface accounts for a large portion of total latency.

Before Optimization – Sequential Calls

The original code calls each interface one after another:

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class DemoTest {
    public static void main(String[] args) throws Exception {
        long beginTime = System.currentTimeMillis();
        int processA = new InterfaceA().process();
        int processB = new InterfaceB().process();
        int result = processA + processB;
        log.info("执行结果:{} 耗时:{}", result, System.currentTimeMillis() - beginTime);
    }

    @Slf4j
    public static final class InterfaceA {
        Integer result = 1;
        public int process() {
            long beginTime = System.currentTimeMillis();
            try { Thread.sleep(2000); } catch (Exception e) { log.error("InterfaceA.process Exception"); }
            log.info("执行接口InterfaceA.process 耗时:{}ms", System.currentTimeMillis() - beginTime);
            return result;
        }
    }

    @Slf4j
    public static final class InterfaceB {
        Integer result = 1;
        public int process() {
            long beginTime = System.currentTimeMillis();
            try { Thread.sleep(2000); } catch (Exception e) { log.error("InterfaceB.process Exception"); }
            log.info("执行接口InterfaceB.process 耗时:{}ms", System.currentTimeMillis() - beginTime);
            return result;
        }
    }
}

Execution result (sequential):

21:40:17.603 [main] INFO DemoTest$InterfaceA - 执行接口InterfaceA.process 耗时:2002ms
21:40:19.612 [main] INFO DemoTest$InterfaceB - 执行接口InterfaceB.process 耗时:2001ms
21:40:19.613 [main] INFO DemoTest - 执行结果:2 耗时:4018

After Optimization – Asynchronous Calls with ThreadPoolExecutor

The refactored code submits each interface call to a fixed‑size thread pool and waits for the futures:

import cn.hutool.core.thread.ThreadFactoryBuilder;
import lombok.extern.slf4j.Slf4j;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

@Slf4j
public class DemoTest {
    private static ThreadPoolExecutor pool = new ThreadPoolExecutor(
            5,
            5,
            60,
            TimeUnit.SECONDS,
            new ArrayBlockingQueue<Runnable>(1000),
            ThreadFactoryBuilder.create().setNamePrefix("线程名称-").build()
    );

    public static void main(String[] args) throws Exception {
        long beginTime = System.currentTimeMillis();
        List<Future<Integer>> futures = new ArrayList<>(2);
        List<Integer> results = new ArrayList<>(2);
        futures.add(pool.submit(() -> new InterfaceA().process()));
        futures.add(pool.submit(() -> new InterfaceB().process()));
        for (Future<Integer> item : futures) {
            results.add(item.get());
        }
        int result = results.get(0) + results.get(1);
        log.info("执行结果:{} 耗时:{}", result, System.currentTimeMillis() - beginTime);
    }

    @Slf4j
    public static final class InterfaceA { /* same as before */ }
    @Slf4j
    public static final class InterfaceB { /* same as before */ }
}

Execution result (parallel):

22:03:43.180 [线程名称-1] INFO DemoTest$InterfaceB - 执行接口InterfaceB.process 耗时:2004ms
22:03:43.180 [线程名称-0] INFO DemoTest$InterfaceA - 执行接口InterfaceA.process 耗时:2004ms
22:03:43.190 [main] INFO DemoTest - 执行结果:2 耗时:2020

Using CompletableFuture (JDK 1.8)

Java 8’s CompletableFuture can further simplify asynchronous composition:

import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;

@Slf4j
public class DemoTest {
    public static void main(String[] args) throws Exception {
        long beginTime = System.currentTimeMillis();
        CompletableFuture<Integer> interfaceFuturesA = CompletableFuture.supplyAsync(() -> new InterfaceA().process());
        CompletableFuture<Integer> interfaceFuturesB = CompletableFuture.supplyAsync(() -> new InterfaceB().process());
        CompletableFuture<List<Integer>> future = CompletableFuture
                .allOf(interfaceFuturesA, interfaceFuturesB)
                .thenApply(none -> {
                    List<Integer> dataList = new ArrayList<>(2);
                    try {
                        dataList.add(interfaceFuturesA.get());
                        dataList.add(interfaceFuturesB.get());
                    } catch (Exception e) {
                        log.error("执行异常");
                    }
                    return dataList;
                })
                .exceptionally(e -> Lists.newArrayList());
        int result = future.get().get(0) + future.get().get(1);
        log.info("执行结果:{} 耗时:{}", result, System.currentTimeMillis() - beginTime);
    }

    @Slf4j
    public static final class InterfaceA { /* same as before */ }
    @Slf4j
    public static final class InterfaceB { /* same as before */ }
}

Result with CompletableFuture:

22:31:44.822 [ForkJoinPool.commonPool-worker-5] INFO DemoTest$InterfaceB - 执行接口InterfaceB.process 耗时:2005ms
22:31:44.822 [ForkJoinPool.commonPool-worker-3] INFO DemoTest$InterfaceA - 执行接口InterfaceA.process 耗时:2002ms
22:31:44.831 [main] INFO DemoTest - 执行结果:2 耗时:2027

Optimization Tips

Use a thread pool to avoid memory‑overflow risks.

Customize the result container according to business needs.

Adjust interface granularity—combine or split calls based on actual workload.

By applying asynchronous execution, developers can significantly cut the total latency of multiple independent service calls while keeping the code maintainable.

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.

JavaPerformance OptimizationBackend DevelopmentThreadPoolAsynchronousCompletableFuture
Selected Java Interview Questions
Written by

Selected Java Interview Questions

A professional Java tech channel sharing common knowledge to help developers fill gaps. Follow us!

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.