Completable Future 가이드 (파트2)

Chanhyeong LEE
3 min readNov 26, 2017

--

파트1에 이은 파트2

연산 로직을 가진 CompletableFuture

앞의 코드이다. 보면 Executor 로 로직을 실행하고 complete 로 결과를 넘겨주는 것을 볼 수 있다. 이런 boilerplate 코드 없이 바로 CompletableFuture 를 만들 수 없을까?

runAsync, supplyAsync 메소드로 바로 연산 로직을 넣어줄 수 있다. 메소드들은 각각 Runnable, Supplier 인터페이스를 받아 ForkJoinPool 에서 로직을 수행한다. (ForkJoinPool 은 그저 JAVA 어플리케이션이 실행되는 컴퓨터에 CPU 수만큼 미리 만들어둔 스레드 풀이라 생각하면 된다.)

Runnable 인터페이스는 옛날 Thread 수행시 사용했던 인터페이스로 반환 값을 없는 것이 특징이다. 그리고 Supplier 는 입력 인자가 없으며 반환 값이 있는 함수형 인터페이스이다. 두 인터페이스 모두 메소드를 하나만 가진 인터페이스이여서 람다 형식으로 표현 가능하다.

비동기 연산 결과 처리하기

비동기 연산 결과 값에 추가적인 처리를 하려면 몇몇 함수에 추가 처리를 해줄 함수를 인자로 넘기면 된다. 그 중 thenApply 메소드는 비동기 연산 결과로 넘어온 값을 입력으로 받고 처리 후 반환하는 함수를 입력으로 받는다. thenApply 메소드는 Future 를 반환하여 그 결과 값을 get 메소드로 받을 수 있다.

만약에 비동기 연산의 결과를 받고 처리 후 아무 것도 반환하기 싫으면 thenAccept 메소드를 이용하면 된다. 이 메소드는 Consumer 함수 인터페이스를 받으며 비동기 연산 결과를 인자로 받으며 Void 를 반환하는 함수를 입력으로 받는다. (파트1에서 말한 Consumer 와는 다르다. 앞서 말한 파트1 은 Consumer 를 Futureget 메소드를 호출하는 쪽으로 생각하고 작성했다. 여기선 함수 인터페이스를 의미한다.)

마지막으로 아무 인자도 받지 않고 그저 Void 를 반환하는 함수를 수행하고 싶으면 thenRun 메소드를 이용하면 된다. 이 함수는 Runnable 인터페이스를 입력으로 받으며 thenRun 메소드가 호출된 Futureget 메소드 호출 이후에 입력 받은 함수를 수행한다.

Future 조합하기

CompletableFuture 의 가장 중요한 부분으로 비동기 연산들 즉, Future 을 조합하는 부분이다. 참고로 조합 후 나온 CompletableFuture 로 또 이어서 조합을 할 수 있으며 이런 방식은 모나딕 디자인 패턴 중 하나이다.

자, 아래 예제는 두 개의 FuturethenCompose 메소드로 조합하는 예제이다. thenCompose 로 조합을 할 때는 하나의 Future 의 결과 값이 다음 Future 로 전달되어 처리 할 수 있도록 하는 조합 방식이다.

앞에서 본 thenApply 메소드와 비슷한데 thenCompose 메소드는 Future 를 반환하는 것이 큰 차이이다. thenCompose 에서 Future 를 반환하면서 비동기 연산을 조합할 수 있음을 의미한다.

만약 두개의 독립적인 Future 를 조합하고자 한다면 thenCombine 메소드를 사용할 수 있다. 이 메소드는 두 개의 Future 를 입력으로 받으며, 3번째 인자로 이 Future 들에서 나온 결과 값들을 처리할 수 있는 함수를 받는다.

이렇게 두 개의 Future 결과를 가지고 무언가하는 경우지만 Future 조합 이후 아무 결과도 반환하지 않는 경우엔 thenAcceptBoth 메소드를 이용할 수 있다.

--

--