Future
Future 형식의 API는 일회성의 값을 처리하는 데 적합하고, 리액티브 형식의 비동기 API 는 자연스럽게 일련의 값을 처리하는데 적합함.
CompletableFuture
작업실행
runAsync()
— 리턴값 없는 경우
supplyAsync()
— 리턴값 있는 경우
후속작업 연계
thenApply()
: input o, return 값 o.thenApplyAsync()
: thenApply() 는 같은 스레드가 후속작업을 이어서 진행하는 반면, thenApplyAsync는 다른 스레드가 작업을 진행하게 됨
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> { System.out.println("Hello: " + Thread.currentThread().getName()); return "Hello"; }).thenApplyAsync((s) -> { System.out.println(Thread.currentThread().getName()); return s.toUpperCase(); }); /* Hello: ForkJoinPool.commonPool-worker-1 ForkJoinPool.commonPool-worker-2 */ // thenApply() 일 경우 두개의 스레드가 같음
thenAccept()
: input o, return x
thenRun()
: input x, return x
CompletableFuture 사이에 조합
thenCompose()
: 두 작업(CompletableFuture)이 서로 이어서 실행하도록 조합
thenCombine()
: 두 작업을 독립적으로 실행하고 둘 다 종료 했을 때 콜백 실행
얘네 둘은 굳이 thenApply() 안쓰고 써야 하는 이유를 잘 모르겠네 (차이점은 thenApply는 함수형태로 콜백을 제공하고, 위에 둘은 CompletableFuture를 제공)
allOf()
- 여러 작업을 모두 실행하고, 모든 작업 결과에 콜백 실행- Returns: a new CompletableFuture that is completed when all of the given CompletableFutures complete
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> { System.out.println("Hello: " + Thread.currentThread().getName()); return "Hello"; }); CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> { System.out.println("World: " + Thread.currentThread().getName()); return "World"; }); List<CompletableFuture<String>> futures = List.of(future, future2); CompletableFuture[] futureArray = futures.toArray(new CompletableFuture[futures.size()]); // thenApply에서의 v는 의미 없는 값임 // allOf 메서드가 실행되고 난 뒤, 새로운 CompletableFuture가 반환되는데, // 이 CompletableFuture의 반환값이라 보면됨(의미x) CompletableFuture<List<String>> list = CompletableFuture.allOf(futureArray) .thenApply((v) -> futures.stream().map(CompletableFuture::join).collect(Collectors.toList())); list.get().forEach(System.out::println); // System.out.println(future.get());
작업결과 반환
- join() : UncheckedException을 던지기 때문에 얘를 사용하는 것이 좋음
- get() : CheckedException을 던지기 때문에 try-catch 구문이나 throws 처리를 해야 함