[Java 8] CompletableFuture - 4 (종료조건) Java

- 출처: 자바 8 in action

- CompletableFuture 종료
앞서 작성한 코드들에서 원격 서비스를 흉내내기 위해 1초 sleep을 주었지만 사실 실제 상황에서는 네트워크 상황이나 다른 변수등 어떤일이 일어날지 알 수 없다. 그래서 원격 서비스를 사용할 때 더 실제와 같은 상황을 부여하기 위해 랜덤하게 sleep을 할당해보자.
getTicketPrice 메소드에 sleep 부분을 아래 코드로 변경하자.
1
2
3
4
5
6
7
int delay = 500 + random.nextInt(2000); 

try {
Thread.sleep(delay);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
앞선 코드는 모든 가격이 조회될때까지 기다렸지만 더 빨리 조회되는 가격정보를 먼저 보여줄 수 있다. 그러려면 CompletableFuture의 Stream을 직접 제어해야 하는데 아래와 같이 Stream을 반환하는 메소드를 추가해보자.
 1
2
3
4
5
6
7
8
9
10
11
public Stream<CompletableFuture<String>> getTicketPriceStream(List<Ticket> tickets){

return tickets.stream()
.map(ticket -> CompletableFuture.supplyAsync(() ->
getTicketPrice(ticket.getFrom(), ticket.getTo())))
.map(future -> future.thenApply(DiscountForm::new))
.map(future -> future.thenCompose((discountForm) ->
CompletableFuture.supplyAsync(() ->
DiscountService.getPriceViaDiscountForm(discountForm)
)));
}
Stream을 반환받으면 아래와 같은 형식으로 사용할 수 있다.
1
2
3
4
5
	CompletableFuture[] futures = airline.getTicketPriceStream(tickets)
.map(f -> f.thenAccept(System.out::println))
.toArray(size -> new CompletableFuture[size]);

CompletableFuture.allOf(futures).join();
thenAccept는 CompletableFuture에 등록된 동작을 소비하는 메소드이다. 그렇다고 thenAccept 메소드만 코딩 후 그대로 실행한다고 해서 결과값이 출력되는 것은 아니다. thenAccept 는 등록된 동작을 어떻게 소비할지만 정의한 상태인것이다. thenAccept는 Comsumer 함수형 인터페이스를 인자로 받으므로 CompletableFuture<Void> 형을 반환하게 된다.
소비하는 동작까지 정했으면 실제로 어떻게 CompletableFuture를 종료할것인지를 정해야 한다. 만약 모든 ticket의 가격을 구하고 싶다면 CompletableFuture.allOf 메소드로 모든 ticket의 비동기 연산이 끝날때까지 기다린다. 얼만큼의 시간이 걸렸는지 더 자세히 파악하기 위해 메소드를 수정해보자.
1
2
3
4
5
6
7
8
9
	long startTime = System.currentTimeMillis();

CompletableFuture[] futures = airline.getTicketPriceStream(tickets)
.map(f -> f.thenAccept(resultPrice -> {
long end = System.currentTimeMillis();
String result = "Date: " + ((end - startTime) / 1000.0) + ", result: " + resultPrice;
System.out.println(result);
}))
.toArray(size -> new CompletableFuture[size]);
- 실행결과
1
2
3
4
5
Date: 1.8, result: KOR,KAZ,0.6158781006883716
Date: 1.825, result: KOR,JPN,0.31299183537878195
Date: 1.951, result: KOR,CHN,0.9042009738962702
Date: 2.018, result: KOR,CHE,0.6109196728742164
Date: 2.836, result: KOR,USA,0.6322615503251896
랜덤으로 수행해서 각 Ticket 마다 가격계산을 완료한 시간이 다르다.
만약 모든 결과를 기다릴 필요 없이 1개의 결과만 받으면 되는 상황이라면 allOf 대신 anyOf를 사용한다.
1
CompletableFuture.anyOf(futures).join();
- 실행결과
1
Date: 1.586, result: KOR,KAZ,0.571177037860831



덧글

댓글 입력 영역