JAVA에서 비동기(Asynchronous) API 호출 예제

자바에서 비동기(Asynchronous) API 호출을 구현하는 가장 일반적이고 현대적인 방법CompletableFuture 클래스를 사용하는 것입니다. 이는 Java 8부터 도입되었으며 비동기 프로그래밍을 위한 강력하고 유연한 도구를 제공합니다.


 

💻 CompletableFuture를 이용한 비동기 API 호출 예제

 

이 예제에서는 가상의 외부 API 호출을 시뮬레이션하고, CompletableFuture.supplyAsync()를 사용하여 해당 작업을 별도의 스레드에서 비동기적으로 실행합니다.

 

1. 코드 예제

 

Java

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;

public class AsyncApiCallExample {

    // 가상의 API 호출 메서드 (시간이 오래 걸리는 작업이라고 가정)
    public static String callExternalApi(String query) {
        System.out.println("🔥 API 호출 시작: " + query + " (Thread: " + Thread.currentThread().getName() + ")");
        try {
            // API 응답 대기 시뮬레이션
            TimeUnit.SECONDS.sleep(2);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        System.out.println("✅ API 호출 완료: " + query + " (Thread: " + Thread.currentThread().getName() + ")");
        return "API 응답 데이터 for " + query;
    }

    public static void main(String[] args) {
        System.out.println("🚀 메인 프로그램 시작 (Thread: " + Thread.currentThread().getName() + ")");

        // 1. CompletableFuture를 사용하여 비동기 호출 시작
        // supplyAsync는 별도의 스레드에서 작업을 실행하고 결과를 CompletableFuture에 담아 반환합니다.
        CompletableFuture<String> futureResult = CompletableFuture.supplyAsync(() -> 
            callExternalApi("User Data Request")
        );

        // 2. 비동기 작업이 진행되는 동안 다른 작업 수행 가능 (논블로킹)
        System.out.println("⏳ API 호출 결과를 기다리지 않고 다른 작업 수행 중...");
        try {
            TimeUnit.MILLISECONDS.sleep(500);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        System.out.println("✅ 다른 작업 완료.");

        // 3. 비동기 작업이 완료된 후 후속 작업 정의 (콜백)
        // thenAccept는 결과가 준비되면 실행될 작업을 정의합니다.
        futureResult.thenAccept(result -> {
            System.out.println("⬇️ CompletableFuture 콜백 실행 (Thread: " + Thread.currentThread().getName() + ")");
            System.out.println("최종 결과 수신: " + result);
        });

        // 4. 결과가 준비될 때까지 메인 스레드 대기 (블로킹, 예제 실행을 위해 필요)
        // 실제 애플리케이션에서는 `.get()`을 호출하는 대신 콜백(`.thenApply`, `.thenAccept` 등)을 주로 사용합니다.
        try {
            // 이 시점에서 메인 스레드는 futureResult가 완료될 때까지 기다립니다.
            // *주의*: 실제 비동기의 이점을 살리려면 메인 스레드에서 바로 `.get()`을 호출하는 것은 피하는 것이 좋습니다.
            futureResult.get(); 
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        }

        System.out.println("🏁 메인 프로그램 종료 (Thread: " + Thread.currentThread().getName() + ")");
    }
}

 

2. 예제 실행 결과 (순서는 다를 수 있음)

 

🚀 메인 프로그램 시작 (Thread: main)
🔥 API 호출 시작: User Data Request (Thread: ForkJoinPool.commonPool-worker-1)
⏳ API 호출 결과를 기다리지 않고 다른 작업 수행 중...
✅ 다른 작업 완료.
✅ API 호출 완료: User Data Request (Thread: ForkJoinPool.commonPool-worker-1)
⬇️ CompletableFuture 콜백 실행 (Thread: ForkJoinPool.commonPool-worker-1)
최종 결과 수신: API 응답 데이터 for User Data Request
🏁 메인 프로그램 종료 (Thread: main)

 

✨ 핵심 개념 설명

JAVA에서 비동기(Asynchronous) API 호출 예제

  • CompletableFuture.supplyAsync(Supplier<T> supplier):
    • Supplier에 정의된 작업을 비동기적으로 실행합니다. (주로 ForkJoinPool의 CommonPool을 사용)
    • 이 작업의 결과를 담을 수 있는 CompletableFuture 객체를 즉시 반환합니다. 호출한 스레드는 블로킹 없이 다음 코드를 계속 실행합니다.
  • .thenAccept(Consumer<? super T> action):
    • 비동기 작업이 성공적으로 완료되었을 때 실행할 후속 작업(콜백)을 정의합니다.
    • 이 작업은 결과를 소비(사용)만 하고 별도의 값을 반환하지 않을 때 사용됩니다.
  • .get():
    • CompletableFuture결과가 나올 때까지 현재 스레드를 블로킹합니다.
    • 비동기 작업의 결과를 기다려야 할 때 사용되지만, 비동기의 이점을 살리려면 가능한 한 콜백 메서드(e.g., thenApply, thenAccept)를 사용하여 블로킹을 최소화하는 것이 좋습니다.

Spring Boot와 같은 프레임워크 환경에서는 RestTemplate 대신 **WebClient**를 사용하여 비동기/논블로킹 API 호출을 구현하거나, @Async 어노테이션을 활용하여 메서드를 비동기적으로 실행할 수도 있습니다.

이 영상은 Java에서 비동기 API 호출을 위해 CompletableFutureRxJava를 사용하는 방법을 비교하여 보여줍니다: Async API Calls in Java: CompletableFuture vs RxJava (3-Min Demo).