CompletableFuture 클래스란?
Java 8부터 도입된 클래스로, 비동기적인 작업을 처리하고 결과를 다루는 데 사용된다.
1. 비동기 실행 방법
1-1) runAsync
비동기로 작업을 실행하고 결과를 반환하지 않고, Runnable 인터페이스를 구현한 람다 표현식으로 정의된다.
CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
// 비동기로 실행될 작업
});
1-2) supplyAsync
비동기로 작업을 실행하고 결과를 제공하는 CompletableFuture를 반환한다. Supplier 인터페이스를 구현한 람다 표현식으로 정의된다.
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
// 비동기로 실행될 작업
return "작업 결과";
});
1-3) submit
ExecutorService를 사용하여 비동기 작업을 실행하고, Future객체를 반환한다. Callable인터페이스를 구현한 람다 표현식으로 정의된다.
ExecutorService executor = Executors.newFixedThreadPool(10);
Future<String> future = executor.submit(() -> {
// 비동기로 실행될 작업
return "작업 결과";
});
1-4) invokeAll
ExecutorService를 사용하여 여러 개의 비동기 작업을 동시에 실행하고, List<Future> 객체를 반환한다. Callable 인터페이스를 구현한 람다 표현식으로 정의된다.
ExecutorService executor = Executors.newFixedThreadPool(10);
List<Callable<String>> tasks = Arrays.asList(
() -> {
// 비동기로 실행될 작업 1
return "작업 1 결과";
},
() -> {
// 비동기로 실행될 작업 2
return "작업 2 결과";
}
);
List<Future<String>> futures = executor.invokeAll(tasks);
2. 비동기 실행 결과 콜백 방법
CompletableFuture를 체인으로 연결하고, 비동기 작업의 결과를 처리하거나 다음 작업을 정의할 수 있다. 콜백 메서드들은 비동기 작업의 완료 시점에 실행되며, 이전 작업의 결과를 입력으로 받아 처리하거나 예외 처리한다.
2-1) thenApply
이전 CompletableFuture의 결과를 입력으로 받아 작업을 처리하고, 결과를 반환하는 CompletableFuture를 생성한다. Function 인터페이스를 구현한 람다 표현식으로 정의된다.
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
// 비동기로 실행될 작업
return 10;
}).thenApply(result -> result * 2);
2-2) thenAccept
이전 CompletableFuture의 결과를 입력으로 받아 작업을 처리하고 결과를 반환하지 않는다. Consumer 인터페이스를 구현한 람다 표현식으로 정의된다.
CompletableFuture<Void> future = CompletableFuture.supplyAsync(() -> {
// 비동기로 실행될 작업
return "작업 결과";
}).thenAccept(result -> {
// 결과를 처리하는 작업
System.out.println("결과: " + result);
});
2-3) thenRun
이전 CompletableFuture의 결과에 상관없이 실행될 작업을 정의한다. 작업은 Runnable 인터페이스를 구현한 람다 표현식으로 정의되고, 결과를 반환하지 않는다.
CompletableFuture<Void> future = CompletableFuture.supplyAsync(() -> {
// 비동기로 실행될 작업
return "작업 결과";
}).thenRun(() -> {
// 이전 작업과 상관없이 실행될 작업
System.out.println("작업이 완료되었습니다.");
});
2-4) exceptionally
CompletableFuture가 예외로 완료된 경우, 예외를 처리하고 대체 결과를 반환한다. Function 인터페이스를 구현한 람다 표현식으로 정의된다.
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
// 비동기로 실행될 작업
throw new RuntimeException("에러 발생");
}).exceptionally(ex -> {
// 예외를 처리하고 대체 결과 반환
System.out.println("에러 발생: " + ex.getMessage());
return -1;
});
3. 조합 처리 방법
3-1) allOf
여러 개의 CompletableFuture들이 모두 완료될 때까지 기다리고, 모든 CompletableFuture가 완료되면
CompletableFuture<Void>를 반환한다. 결과값은 null 이다.
CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> "Result 1");
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> "Result 2");
CompletableFuture<Void> allFutures = CompletableFuture.allOf(future1, future2);
allFutures.thenRun(() -> {
System.out.println("All futures completed.");
});
3-2) anyOf
여러 개의 CompletableFuture들 중 가장 빨리 완료되는 하나의 CompletableFuture를 반환한다. 어떤 CompletableFuture가 먼저 완료되더라도 첫 번째 완료된 결과를 반환한다.
CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> "Result 1");
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> "Result 2");
CompletableFuture<Object> anyFuture = CompletableFuture.anyOf(future1, future2);
anyFuture.thenAccept(result -> {
System.out.println("First completed future result: " + result);
});
3-3) thenCompose
두 작업이 이어서 실행하도록 조합하며, 앞선 작업의 결과를 받아서 사용할 수 있다. Function 인터페이스를 구현한 람다 표현식으로 정의된다.
CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> 10);
CompletableFuture<CompletableFuture<String>> futureCompose = future1.thenApply(result -> {
CompletableFuture<String> nestedFuture = CompletableFuture.supplyAsync(() -> "Result: " + result);
return nestedFuture;
});
3-4) thenCombine
두 작업을 독립적으로 실행하고, 둘 다 완료되었을 때 콜백을 실행하며 함수의 실행 결과를 포함하는 새로운 CompletableFuture를 반환한다.
CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> 10);
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> "Hello");
CompletableFuture<String> combinedFuture = future1.thenCombine(future2, (result1, result2) -> result1 + " " + result2);
// 10 Hello
4. 활용
4-1) 비동기 API 호출 응답 처리
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
// 외부 API 호출 또는 데이터베이스 쿼리 등의 I/O 작업 수행
String result = someExternalService.callApi();
return result;
});
future.thenAccept(result -> {
// 비동기 작업이 완료된 후 결과 처리
System.out.println("API 응답 결과: " + result);
});
- supplyAsync : 비동기 작업을 실행하고, 외부 API 호출 또는 데이터베이스 쿼리 등의 I/O 작업을 수행한다.
- thenAccept : 작업이 완료된 후에 결과를 처리하는 콜백을 등록한다.
4-2) 병렬 작업 처리
CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> {
// 작업 1
return 10;
});
CompletableFuture<Integer> future2 = CompletableFuture.supplyAsync(() -> {
// 작업 2
return 20;
});
CompletableFuture<Integer> combinedFuture = future1.thenCombine(future2, (result1, result2) -> {
// 두 작업의 결과를 조합하여 처리
return result1 + result2;
});
combinedFuture.thenAccept(result -> {
// 조합된 결과 처리
System.out.println("두 작업의 합: " + result);
});
- supplyAsync : 각각의 작업을 병렬로 실행한다.
- thenCombine : 두 작업의 결과를 조합하여 새로운 CompletableFuture를 생성한다.
- thenAccept : 조합된 결과를 처리하는 콜백을 등록한다.
반응형
'Java' 카테고리의 다른 글
[Spring Boot] 내장 웹 서버 개념 및 활용(서버 변경, 포트 변경) (0) | 2023.06.11 |
---|---|
[Spring Boot] 자동 설정 JAR 파일 생성 및 사용 방법 (0) | 2023.06.05 |
[Java] Optional 클래스 개념 및 사용 방법 (0) | 2023.05.31 |
[Java] 날짜 및 시간 API (Date and Time API) 사용 방법 (0) | 2023.05.30 |
[Java] 함수형 인터페이스 종류 및 사용 방법 (0) | 2023.05.26 |