본문 바로가기
language/java

CompletableFuture 완벽 이해하기

by 죄니안죄니 2026. 6. 1.
반응형

CompletableFuture 완벽 이해하기

이전 글에서:

  • ExecutorService
  • Future
  • ThreadPoolExecutor

를 배웠다.

그런데 실무에서는 Future를 거의 직접 쓰지 않는다.

왜냐하면 Future에는 치명적인 문제가 있기 때문이다.

그래서 Java 8에서 등장한 것이:

CompletableFuture

이다.

현재 Spring Boot 실무 비동기 처리에서 가장 많이 사용하는 기술 중 하나다.


1. Future의 문제

예제.

 
ExecutorService executor =
    Executors.newFixedThreadPool(10);

Future<String> future =
    executor.submit(() -> {

        Thread.sleep(3000);

        return "완료";
    });
 

결과 얻기.

 
String result =
        future.get();
 

2. 문제

 
future.get();
 

작업 끝날 때까지 대기
 

한다.


3. 이것을

Blocking
 

이라고 한다.


예:

3초 작업

↓

3초 동안 Thread 정지
 

4. 또 다른 문제

Future끼리 연결이 안 된다.

예:

DB 조회
 ↓
API 호출
 ↓
결과 가공
 

Future는 이런 체인을 만들기 어렵다.


5. 그래서 등장

CompletableFuture


6. CompletableFuture란?

한 줄 정의.

비동기 작업을 조합(Compose)할 수 있는 Future
 

7. 가장 기본 예제

 
CompletableFuture<String> future =
    CompletableFuture.supplyAsync(() -> {

        return "Hello";
    });
 

8. 결과 받기

 
String result =
        future.get();
 

출력.

Hello
 

9. supplyAsync()

매우 중요.


의미.

반환값 있는 비동기 작업
 

예:

 
CompletableFuture<Integer> future =
    CompletableFuture.supplyAsync(() -> {

        return 100;
    });
 

10. runAsync()

반환값 없는 작업.


 
CompletableFuture.runAsync(() -> {

    System.out.println("실행");
});
 

11. 차이

메서드반환값
runAsync() 없음
supplyAsync() 있음

12. 진짜 강점

작업 연결 가능.


예:

 
DB 조회
 ↓
가공
 ↓
응답 생성
 

13. thenApply()

가장 많이 사용.


 
CompletableFuture<String> future =
    CompletableFuture.supplyAsync(() -> {

        return "hello";
    })
    .thenApply(value -> {

        return value.toUpperCase();
    });
 

결과.

HELLO
 

14. 흐름

hello
 ↓
thenApply
 ↓
HELLO
 

15. thenAccept()

결과 소비.


 
future.thenAccept(value -> {

    System.out.println(value);
});
 

반환 없음.


16. thenRun()

결과도 필요 없고

그냥 다음 작업.


 
future.thenRun(() -> {

    System.out.println("완료");
});
 

17. 실무 예제

회원 조회.


 
CompletableFuture<User> future =
    CompletableFuture.supplyAsync(
        () -> userRepository.findById(1L)
    );
 

가공.

 
future.thenApply(
    user -> user.getName()
);
 

18. thenCompose()

면접 단골.


예:

API1 호출
 ↓
결과 이용
 ↓
API2 호출
 

19. 잘못된 방식

 
CompletableFuture<
    CompletableFuture<String>
>
 

생성.


중첩 Future.


20. 해결

 
thenCompose()
 

예:

 
CompletableFuture<String> future =

    getUser()

    .thenCompose(
        user -> getOrder(user)
    );
 

21. 의미

Future 평탄화
 

22. thenApply vs thenCompose

매우 중요.


thenApply

 
A → B
 

thenCompose

 
A → Future<B>
 

23. 그림

thenApply

A
 ↓
B
 

thenCompose

A
 ↓
Future<B>
 

24. allOf()

실무 중요.


여러 작업 병렬 실행.


 
CompletableFuture<User> userFuture =
    getUser();

CompletableFuture<Order> orderFuture =
    getOrder();
 

25. 병렬 실행

 
CompletableFuture.allOf(
    userFuture,
    orderFuture
);
 

26. 의미

둘 다 끝날 때까지 대기
 

27. 그림

User 조회
     ↘
      allOf
     ↗
Order 조회
 

28. 실무 예시

쇼핑몰.


회원 정보 조회

주문 조회

포인트 조회
 

동시에 수행.


29. 순차 실행

1초
+
1초
+
1초

=
3초
 

30. 병렬 실행

1초
 

정도.


31. exceptionally()

예외 처리.


 
future.exceptionally(ex -> {

    log.error("오류", ex);

    return "기본값";
});
 

32. 의미

예외 발생 시 대체값 반환
 

33. handle()

더 강력함.


 
future.handle((result, ex) -> {

});
 

둘 다 접근 가능.


정상 결과
 

또는

예외
 

34. whenComplete()

후처리.


 
future.whenComplete(
    (result, ex) -> {

        log.info("완료");
    }
);
 

35. ForkJoinPool

매우 중요.


기본적으로.

 
CompletableFuture.supplyAsync(...)
 

ForkJoinPool.commonPool()
 

사용.


36. 문제

실무에서는 위험.


공용 Pool 사용.


트래픽 많으면.

서로 영향
 

줄 수 있음.


37. 실무 방식

Executor 지정.


 
CompletableFuture.supplyAsync(
    () -> doWork(),
    executor
);
 

38. Spring @Async 연결

실무 핵심.


 
@Async
public CompletableFuture<User>
findUser() {

    return CompletableFuture.completedFuture(
        user
    );
}
 

Spring 내부.

ThreadPoolTaskExecutor
 

사용.


39. completedFuture()

즉시 완료.


 
CompletableFuture.completedFuture(
    "OK"
);
 

이미 완료된 Future 반환.


40. Future vs CompletableFuture

항목FutureCompletableFuture
결과 조회 O O
체이닝 X O
예외 처리 제한적 강력
병렬 조합 X O
실무 사용 적음 많음

41. 면접 단골 질문

Q. Future와 CompletableFuture 차이는?

CompletableFuture는
비동기 작업 조합 가능
 

Q. thenApply와 thenCompose 차이는?

thenApply
=
값 변환

thenCompose
=
Future 연결
 

Q. allOf는?

여러 Future 병렬 처리
 

Q. supplyAsync 기본 ThreadPool은?

ForkJoinPool.commonPool()
 

Q. 실무에서 supplyAsync만 쓰나요?

아니오

Executor 지정
 

42. 실무 예제

매우 흔한 패턴.

 
CompletableFuture<User> user =
        getUser();

CompletableFuture<Order> order =
        getOrder();

CompletableFuture<Point> point =
        getPoint();

CompletableFuture.allOf(
        user,
        order,
        point
).join();
 

기존.

1초
+
1초
+
1초

=
3초
 

병렬.

약 1초
 

43. 지금까지 흐름 연결

Thread

↓

Runnable

↓

ExecutorService

↓

ThreadPoolExecutor

↓

Future

↓

CompletableFuture
 

44. 핵심 흐름 요약

비동기 작업 생성
 ↓
CompletableFuture
 ↓
thenApply
 ↓
thenCompose
 ↓
allOf
 ↓
exceptionally
 ↓
완료
 

45. 가장 중요한 핵심 한 줄

CompletableFuture는 Future의 한계를 해결하여 비동기 작업의 조합, 병렬 처리, 예외 처리, 후속 작업 연결을 가능하게 하는 Java의 현대적인 비동기 프로그래밍 도구이다.
 

46. 다음 글 예고

다음 글은:

ForkJoinPool

이다.

여기서부터는:

Work Stealing
RecursiveTask
RecursiveAction
Parallel Stream
CompletableFuture
 

가 모두 어떻게 연결되는지 배우게 된다.

그리고 왜 parallelStream()이 내부적으로 ForkJoinPool을 사용하는지도 이해하게 된다.

반응형

'language > java' 카테고리의 다른 글

ReentrantLock 완벽 이해하기  (0) 2026.06.01
ForkJoinPool 완벽 이해하기  (0) 2026.06.01
ThreadPool 구조 완벽 이해하기  (0) 2026.06.01
ExecutorService 완벽 이해하기  (0) 2026.06.01
Thread-safe 컬렉션 완벽 이해하기  (0) 2026.05.29

댓글