<Java> CompletableFuture
by BFine가. 비동기 처리에 결과를 또 사용해야 하는데..
a. FutureTask 예제
public static void main(String[] args) throws InterruptedException, ExecutionException {
ExecutorService executorService = Executors.newSingleThreadExecutor();
Future<String> submit1 = executorService.submit(()->addWord("","hello"));
final String hello = submit1.get();
System.out.println(hello+" "+Thread.currentThread());
Future<String> submit2 = executorService.submit(()->addWord(hello,"world"));
final String helloWorld = submit2.get();
System.out.println(helloWorld+" "+Thread.currentThread());
Future<String> submit3 = executorService.submit(()->addWord(helloWorld,"happy"));
final String helloWorldHappy = submit3.get();
System.out.println(helloWorldHappy+" "+Thread.currentThread());
executorService.shutdownNow();
}
public static String addWord(String target, String word){
System.out.println(word +" 추가 " + Thread.currentThread());
return target+" "+word;
}
- 비동기 처리한 결과 데이터를 이용해서 또 비동기 처리해야하는 경우를 만들어 보았다. 불필요하게 Main 스레드에서 .get() 하고 있는 것을 볼 수 있다.
- 비동기 처리를 위한 비슷한 부가적인 코드들이 생겨 로직이 지저분해졌다.
=> Spring 에서는 ListenableFuture 에서 Callback 지원하지만 이런 처리가 많아질수록 Callback Hell이 발생한다.
나. CompletableFuture 란
a. 무엇인가?
- java 8 부터 추가된 Future의 구현체로 위의 문제를 CompletionStage를 통해 chain 형태로 해결할 수 있다.
b. CompletionStage
- 이 인터페이스는 비동기 처리 및 후 처리를 위한 다양한 메서드들을 보유하고 있다.
- 이를 구현하고 있는 CompletableFuture 메서드들을 살펴보면 CompletableFuture 자체를 return으로 사용하는 것을 볼 수 있다.
- 위의 코드를 살펴보면 CompleteFuture 를 생성하고 여기에 결과(or 실행)을 담고 생성한 CompleteFuture 자체를 반환하고 있다.
- 즉 CompletionStage는 자기자신의 참조를 통해 비동기 연산의 결과 값을 chain 형태로 활용할 수 있도록 만들어주는 역할을 한다.
c. 예제 바꿔보기
public static void main(String[] args) throws ExecutionException, InterruptedException {
String helloWorldHappy = CompletableFuture.supplyAsync(() -> addWord("", "hello"))
.thenApply(hello -> addWord(hello, "world"))
.thenApply(helloWorld -> addWord(helloWorld, "happy"))
.get();
System.out.println(helloWorldHappy+" "+Thread.currentThread());
}
public static String addWord(String target, String word){
System.out.println(word +" 추가 " + Thread.currentThread());
return target+" "+word;
}
- CompletableFuture 를 이용해 chain 형태로 비동기 연산의 결과를 간단하게 처리 할 수가 있다.
- 내부동작을 좀 더 살펴보자
- .supplyAsync 먼저 살펴보면 내부적으로 CompletableFuture를 생성하고 전달한 lamda 와 함께 AsyncSupply를 생성하여 비동기로 처리한다.
- AsyncSupply 는 CompletableFuture 의 내부에 존재하는 클래스로 Runnable을 구현하고 있어 비동기 실행이 가능하다.
- 다시 넘어와서 .thenApply를 살펴보면
- 위의 .supplyAsync 의 결과인 CompletableFuture가 this인 것을 볼 수 있고 .thenApply의 결과는 dependents로 추가되는 것을 볼 수 있다.
- 이런 형태로 CompletableFuture 는 비동기 처리 연산을 연결지어 하나의 chain 형태로 처리할 수 있도록 해준다
'공부 > Java' 카테고리의 다른 글
<Java> 그룹으로 묶어서 정렬하기 (2) | 2023.01.23 |
---|---|
<Java> Future (0) | 2022.05.06 |
<Java> Thread 와 비동기 (0) | 2022.01.20 |
ForkJoinPool의 Thread Size 고정이 안되는 경우 (3) | 2021.02.26 |
<모던자바인액션> Stream API, JMH, Parallel Stream (0) | 2021.02.21 |
블로그의 정보
57개월 BackEnd
BFine