1. CompletableFuture 체이닝과 조합
복잡한 비동기 작업 흐름을 구성하는 방법을 알아봅시다.
public class AsyncOperations {
public CompletableFuture fetchUserData(String userId) {
return CompletableFuture.supplyAsync(() -> {
// 사용자 데이터 비동기 조회
return "User data for " + userId;
});
}
public CompletableFuture processUserData(String userData) {
return CompletableFuture.supplyAsync(() -> {
// 사용자 데이터 처리
return "Processed: " + userData;
});
}
public CompletableFuture notifyUser(String processedData) {
return CompletableFuture.supplyAsync(() -> {
// 사용자 알림
return "Notified user with: " + processedData;
});
}
public CompletableFuture completeUserFlow(String userId) {
return fetchUserData(userId)
.thenCompose(this::processUserData)
.thenCompose(this::notifyUser)
.exceptionally(ex -> "Error: " + ex.getMessage());
}
}
2. 커스텀 Executor 활용
CompletableFuture와 함께 사용자 정의 Executor를 활용하여 성능을 최적화합니다.
public class CustomExecutorExample {
private static final Executor CUSTOM_EXECUTOR = new ThreadPoolExecutor(
10, 50, 60L, TimeUnit.SECONDS, new LinkedBlockingQueue<>(100),
new ThreadPoolExecutor.CallerRunsPolicy());
public CompletableFuture performTask(String input) {
return CompletableFuture.supplyAsync(() -> {
// 시간이 걸리는 작업 수행
return "Result: " + input;
}, CUSTOM_EXECUTOR);
}
public void executeMultipleTasks() {
List inputs = Arrays.asList("Task1", "Task2", "Task3");
List<CompletableFuture> futures = inputs.stream()
.map(this::performTask)
.collect(Collectors.toList());
CompletableFuture allOf = CompletableFuture.allOf(
futures.toArray(new CompletableFuture));
allOf.join(); // 모든 작업이 완료될 때까지 대기
List results = futures.stream()
.map(CompletableFuture::join)
.collect(Collectors.toList());
results.forEach(System.out::println);
}
}
3. 고급 에러 처리 전략
비동기 작업에서의 효과적인 에러 처리 방법을 알아봅니다.
public class AdvancedErrorHandling {
public CompletableFuture reliableAsyncOperation() {
return CompletableFuture.supplyAsync(() -> {
if (Math.random() < 0.5) throw new RuntimeException("Random failure");
return "Success";
}).handle((result, ex) -> {
if (ex != null) {
logger.error("Operation failed", ex);
return "Fallback result";
}
return result;
}).thenApply(result -> {
// 추가 처리
return "Processed: " + result;
}).orTimeout(5, TimeUnit.SECONDS)
.exceptionally(ex -> {
if (ex instanceof TimeoutException) {
return "Operation timed out";
}
return "Unexpected error: " + ex.getMessage();
});
}
}
결론
CompletableFuture와 비동기 프로그래밍 기법을 마스터하면 복잡한 비동기 작업 흐름을 효과적으로 관리할 수 있습니다. 커스텀 Executor 활용, 체이닝과 조합, 그리고 고급 에러 처리 전략을 통해 더욱 견고하고 효율적인 비동기 애플리케이션을 개발할 수 있습니다.