-
Java CompletableFuture 정리백엔드/Spring 2025. 6. 15. 19:06
Java CompletableFuture 정리 (내부 구조 중심)
1. 기본 개념
1.1 정의
CompletableFuture<T>는 Java 8에 도입된 Future의 확장형으로, 비동기 작업을 선언적이고 함수형 스타일로 구성할 수 있도록 설계된 클래스.
비동기 작업을 명시적으로 조합하고 처리할 수 있도록 다양한 메서드를 제공1.2 목적
- 비동기 및 논블로킹 로직을 단순하고 명확하게 구성
- 다중 작업의 병렬 처리
- 콜백 체이닝을 통한 복잡한 플로우 컨트롤 지원
2. 주요 생성 메서드
2.1 supplyAsync
CompletableFuture<String> cf = CompletableFuture.supplyAsync(() -> "hello");- 반환값 있는 비동기 작업 시작
- 내부적으로 common ForkJoinPool에 작업 제출
2.2 runAsync
CompletableFuture<Void> cf = CompletableFuture.runAsync(() -> doSomething());- 반환값 없는 비동기 작업
3. 콜백 체이닝
3.1 주요 메서드
메서드 설명 thenApply 이전 결과를 가공해 반환값 전달 thenAccept 이전 결과를 소비 (반환 없음) thenRun 입력 없는 새로운 Runnable 실행 thenCombine 두 Future 결과를 조합 thenCompose 다음 CompletableFuture로 이어붙임 3.2 Completion
CompletableFuture는 내부적으로Completion이라는 콜백 체인을 유지한다.- 각 future가 완료되면 자신의 stack에 등록된 Completion의
tryFire()가 실행된다.
4. allOf() 내부 구조
4.1 목적
- 여러 CompletableFuture의 완료를 기다린 뒤 한 번에 처리
4.2 allOf 메서드 구현
public static CompletableFuture<Void> allOf(CompletableFuture<?>... cfs) { return (cfs.length == 0) ? completedFuture(null) : andTree(cfs, 0, cfs.length - 1); }4.3 andTree 구조
static CompletableFuture<Void> andTree(CompletableFuture<?>[] cfs, int lo, int hi) { CompletableFuture<Void> d = new CompletableFuture<>(); if (lo > hi) { d.result = NIL; // 아무 작업도 없으면 즉시 완료 } else { int mid = (lo + hi) >>> 1; CompletableFuture<?> a = (lo == mid ? cfs[lo] : andTree(cfs, lo, mid)); CompletableFuture<?> b = (lo == hi ? a : hi == mid + 1 ? cfs[hi] : andTree(cfs, mid + 1, hi)); if (!d.biRelay(a, b)) { BiRelay<?,?> c = new BiRelay<>(d, a, b); a.bipush(b, c); c.tryFire(SYNC); } } return d; }4.4 BiRelay
BiRelay<T,U>는 두 CompletableFuture가 모두 완료되었는지 확인하는 Completion 노드다.둘 중 하나가 완료되면
bipush()로 등록된 다른 Future의 완료를 대기한다.둘 다 완료되면
tryFire()가 호출되고CompletableFuture<Void>전체가 complete된다.allOf(...)는 단일 CompletableFuture
를 리턴하는데, 내부적으로는 균형 이진 트리 형태의 BiRelay 힙을 구성하고,
자식 Future들이 모두 완료된 시점에 루트 Future를 완료하게 설계되어 있음
5. 동작 방식: 콜백 기반
5.1 postComplete()
- Future가 완료되면
postComplete()호출 - stack에 등록된 모든
Completion객체의tryFire()순차 실행
5.2 polling이 아님
- 완료 여부를 지속적으로 확인하는 폴링 방식이 아님
- 하나의 Future가 완료되면 콜백이 자동 실행됨
6. 예외 처리
6.1 get() vs join()
get()은InterruptedException,ExecutionException을 던지는 checked 예외join()은CompletionException을 던지는 unchecked 예외 (실무에서 주로 사용)
6.2 exceptionally / handle
cf.exceptionally(ex -> { log.error("예외 발생", ex); return "기본값"; });7. 스레드풀
7.1 기본 동작
- Executor를 명시하지 않으면
ForkJoinPool.commonPool()사용
7.2 Executor 지정
CompletableFuture.supplyAsync(() -> ..., myExecutor);8. 정리
CompletableFuture는 비동기 작업을 구성할 수 있게 도와줌allOf()는 작업들을 트리 구조로 묶어 병렬 완료를 감지하며, 콜백 기반으로 트리거됨join()으로 결과를 수집하고 예외를 핸들링할 수 있으며, 내부적으로 polling 없이 Completion 노드 체인으로 처리됨
'백엔드 > Spring' 카테고리의 다른 글