모던 자바인 액션에서 CompletableFuture를 제대로 이해하고 사용하지 못했다. CompletableFuture의 Spring 버전인 ListenableFuture를 사용할 일이 있었는데 사실상 제대로된 에러 처리도 할 수 없었다. 그만큼 CompletableFuture에 대한 이해도 부족했던 것 이다. 그래서 다시 한번 Future부터 CompletableFuture까지의 발전 과정을 살펴보고 자바가 비동기를 대하는 자세를 알아볼 것이다.
1.
동기, 비동기? 블록킹, 논-블록킹?
2.
Future발전 이전의 Thread사용
3.
Thread와 ThreadPool
4.
Future의 활용
5.
CompletableFuture?
6.
CompletableFuture를 활용한 예제
들어가기 전
동기, 비동기의 차이점?
블록킹과 논-블록킹의 차이점? + 비동기
메서드가 동작하는 곳에서 먼저 최종 결과를 주기 전에 메서드로 부터 임의의 결과를 반환 받는 것 결과적으로 주는 쪽에서 동기로 받을 것인지 비동기로 줄 것 인지를 결정하면 된다.
블록킹의 경우에는 비동기 동작 수행 중에 아무 작업도 못한다.
논-블록킹의 경우에는 비동기 동작 수행 중 다른 작업을 하고 있고 끝나갈 때 재 조회를 통하여 메서드의 결과를 다시 반환 받는다
Future발전 이전의 Thread를 직접 사용했을 경우
Thread 대신 ThreadPool
Thread 직접 쓰지 말고 Future와 ThreadPool을 써보자?
•
Future는 비동기적인 연산의 결과를 표현한다.
•
Future를 이용하면 멀티쓰레드 환경에서 데이터를 다른 쓰레드에 전달할 수 있다.
•
Future는 Thread-Safe하다.
•
Future를 이용하면 쓰레드를 이용하여 리턴을 받기 쉬워진다.
CompletableFuture? Future보다 좋은건가?
CompletableFuture를 사용하면 Future의 결과를 명시적으로 사용 가능 하다.
•
Future에서 스레드에서 완료된 연산을 다른 연산으로 넘겨야 하는 상황에서 CompletableFuture는 유용하다. CompletableFuture에 의하여 비동기 처리가 완료된 작업들은 다른 연산이 실행될 수 있다.
•
Executor 인수가 없는 모든 비동기 메서드는 ForkJoinPool.commonPool()을 사용하여 수행된다.
CompletableFuture의 주요 메서드
•
CompletableFuture< U > completedFuture(U value)
비동기 작업이 완료된 상태의 CompletableFuture를 반환한다.
•
boolean complete( T value )
완료가 되지 않은 경우 비동기 결과를 value로 쓴다. get() 메서드를 호출하는 경우 get() 메서드의 결과로 value가 리턴된다. 만약 메서드의 호출로 인해 CompletableFuture가 완료 상태로 변환된 경우 true를 리턴한다.
•
boolean completeExceptionally(Throwable ex)
아직 비동기 호출이 완료되지 않은 경우 get() 및 관련 메서드의 호출이 지정된 예외를 throw 하도록 한다.
CompletableFuture정적 메서드를 통하여 CompletableFuture 생성하는 메서드
•
CompletableFuture< Void > runAsync(Runnable runnable)
비동기 작업을 수행하고, CompletableFuture 객체를 리턴한다. 리턴된 CompletableFuture는 비동기 작업이 완료된 후에 완료된다. 비동기 작업은 ForkJoinPool.commonPool() (CompletableFuture 초기 설명에서 말한 Executor로 할당 받지 않은 리턴된 CompletableFuture가 이에 해당)에서 실행된다.
•
CompletableFuture< Void > runAsync(Runnable runnable, Executor executor)
비동기 작업을 ForkJoinPool.commonPool() 이 아닌 Executor에서 실행(인수에 Executor을 넣어줌으로 가능)
•
CompletableFuture< U > supplyAsync(Supplier< U > supplier)
runAsync(Runnable runnable) 과 동일, 하지만 인수로 Supplier를 받기 때문에 비동기 수행 결과를 받을 수 있다(return이 존재함, CompletableFuture< U > 타입과 CompletableFuture< Void >의 차이).
•
CompletableFuture< U > supplyAsync(Supplier< U > supplier, Executor executor)
runAsync(Runnable runnable, Executor executor) 과 동일, 하지만 Supplier를 인수로 받고 리턴이 존재함
예제
예제 준비물
커피 전문점에서 인기 커피를 주문하면 번들도 같이 추천해주는 시스템을 만들었다. 인기 커피를 찾는데 걸리는 시간은 2초, 번들을 추천해주는데 걸리는 시간은 3초이다. 이 두 가지 서비스를 이용하여 동기, 비동기, 블록킹, 논블록킹을 모두 구현해볼것이다.