1. CompletableFuture 사용
CompletableFuture는 Java 8부터 도입된 기능으로, 비동기 작업을 쉽게 처리할 수 있게 해줍니다.
예제 코드
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
public class AsyncApiExample {
public static void main(String[] args) throws ExecutionException, InterruptedException {
// API 호출 작업 정의
CompletableFuture<String> api1 = CompletableFuture.supplyAsync(() -> callApi("API 1"));
CompletableFuture<String> api2 = CompletableFuture.supplyAsync(() -> callApi("API 2"));
CompletableFuture<String> api3 = CompletableFuture.supplyAsync(() -> callApi("API 3"));
// 모든 작업 완료 후 처리
CompletableFuture<Void> allOf = CompletableFuture.allOf(api1, api2, api3);
allOf.join(); // 모든 작업이 완료될 때까지 대기
// 결과 수집
String result1 = api1.get();
String result2 = api2.get();
String result3 = api3.get();
System.out.println("Result 1: " + result1);
System.out.println("Result 2: " + result2);
System.out.println("Result 3: " + result3);
}
private static String callApi(String apiName) {
try {
// API 호출 시 지연 시간 시뮬레이션
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return apiName + " response";
}
}
2. ExecutorService 사용
ExecutorService를 사용하면 스레드 풀을 활용하여 비동기 작업을 수행할 수 있습니다.
예제 코드
import java.util.concurrent.*;
public class AsyncApiExample {
public static void main(String[] args) throws InterruptedException, ExecutionException {
ExecutorService executorService = Executors.newFixedThreadPool(3);
// API 호출 작업 제출
Future<String> future1 = executorService.submit(() -> callApi("API 1"));
Future<String> future2 = executorService.submit(() -> callApi("API 2"));
Future<String> future3 = executorService.submit(() -> callApi("API 3"));
// 결과 수집
String result1 = future1.get();
String result2 = future2.get();
String result3 = future3.get();
System.out.println("Result 1: " + result1);
System.out.println("Result 2: " + result2);
System.out.println("Result 3: " + result3);
// 스레드 풀 종료
executorService.shutdown();
}
private static String callApi(String apiName) {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return apiName + " response";
}
}
3. Reactive Streams 사용 (Project Reactor)
리액티브 프로그래밍은 비동기 데이터를 처리하는 데 적합합니다. Project Reactor는 이를 지원하는 강력한 도구입니다.
예제 코드
import reactor.core.publisher.Flux;
public class AsyncApiExample {
public static void main(String[] args) {
// 비동기 API 호출
Flux<String> apiCalls = Flux.just("API 1", "API 2", "API 3")
.flatMap(api -> Flux.fromCallable(() -> callApi(api)).subscribeOn(reactor.core.scheduler.Schedulers.boundedElastic()));
// 결과 출력
apiCalls.collectList().block().forEach(System.out::println);
}
private static String callApi(String apiName) {
try {
Thread.sleep(2000); // API 호출 시 지연 시간 시뮬레이션
} catch (InterruptedException e) {
e.printStackTrace();
}
return apiName + " response";
}
}
각 방법의 장단점
방법 장점 단점
CompletableFuture | 간단하고 명확한 코드 | 복잡한 에러 처리 시 코드가 복잡해질 수 있음 |
ExecutorService | 세밀한 스레드 풀 관리 가능 | 코드가 약간 더 장황해질 수 있음 |
Reactive Streams | 대규모 데이터 처리 및 스트림 처리에 적합 | 러닝 커브가 있음 |
반응형
'Coding > Java' 카테고리의 다른 글
[Java/MyBatis] MyBatis <foreach>에서 #{}와 ${} 차이, 그리고 item 두 번 쓰기 (0) | 2025.04.05 |
---|---|
[Java] 리스트의 요소가 다른 리스트에 포함되지 않는지 확인 (Collections.disjoint()) (1) | 2025.03.22 |
[Java/JPA] JPQL 파라미터 바인딩 (위치 기반) (0) | 2024.04.11 |
[Java] String to Date (0) | 2024.04.11 |
[Java] 문자열을 timestampz 형식으로 변경 (0) | 2024.04.02 |