CompletableFuture 클래스
자바에서 지원하는 비동기 프로그래밍
자바에서 비동기 프로그래밍을 지원하는 인터페이스로는 Future가 있습니다.
Future는 시간이 오래 걸리는 작업의 결과를 얻기위해서 뒤의 작업들이 기다리는 것을 해결하고자
시간이 오래걸리는 작업을 다른 스레드에 할당하고 나머지 스레드로 뒤의 연산들을 진행하는 역할을 합니다.
하지만 뒤의 연산중 시간이 오래걸리는 작업의 결과물이 필요할 경우에는 Future.get()을 사용해서 결과값을 가져오지만
만약 아직 작업이 끝나지 않았다면 뒤의 연산들을 대기시킵니다.(Block시킨다는 뜻입니다.)
CompletableFuture 클래스
위의 문제를 해결하기 위해서 CompletableFuture 클래스를 사용합니다.
CompletableFuture 클래스의 기능으로는 결과를 얻는데 오래걸리는 작업의 결과를 Future 인스턴스로 반환합니다.
즉 Future 인스턴스를 반환함으로써 다른 스레드를 사용해 작업을 계속 처리할 수 있게 되었습니다.
병렬처리 vs CompletableFuture 클래스
Stream에서 parallelStream()을 사용하면 Stream의 연산들을 병렬적으로 처리할 수 있습니다.
그렇다면 병렬 스트림을 사용하는 것이 CompletableFuture 클래스를 사용하는 것과 같은 효과를 볼 수 있을 것입니다.
하지만 병렬 스트림은 스레드의 개수가 고정적입니다.
스레드의 개수가 고정적이라는 것은 병렬 스트림의 스레드개수가 100개일 때 사용자가 100명의 고객 정보를 요청했을 때 병렬 스트림과 CompletableFuture 클래스의 성능 차이가 없습니다. 하지만 사용자가 1000명의 고객 정보를 요청한다면
병렬 스트림은 스레드의 개수가 100개로 고정되어있어서 1000개의 작업을 100개의 스레드로 나눠 작업해야 합니다.
반면 CompletableFuture 클래스는 Executor(쉽게 말해 스레드의 개수를 지정하는 변수)를 개발자가 정의할 수 있습니다.
따라서 사용자의 요청에 맞춰서 스레드를 결정할 수 있습니다. 요청의 수가 많아질수록 두 방식의 성능차이는 커집니다.
CompletableFuture 클래스 사용
CompletableFuture 클래스를 사용하는 이유를 알았으니 실제 사용방법을 보겠습니다.
위의 2코드는 순차적일때와 CompletableFuture 클래스를 이용했을 때를 구현한 것입니다.
결과 시간을 확인해보면 CompletableFuture 클래스가 성능이 안좋은 것을 알 수 있습니다.
이유는 작업이 간단하고 처리 작업수가 적기 때문입니다.
위에 보이듯이 CompletableFuture 클래스를 사용할 때는 직접 new CompletableFuture<>()를 하기도 하지만
CompletableFuture.suppAsync를 사용합니다.
CompletableFuture 클래스를 간단하게 구현할 수 있다는 장점이 있습니다.
다음으로 CompletableFuture 클래스의 메서드들입니다.
.thenApply | (Function<T,R>) | CompletableFutured의 연산이 끝나면 인수로 받은 함수를 적용 |
.thenCompose | ( CompletableFuture 클래스 ) | CompletableFuture 클래스가 인수로 다른 CompletableFuture 클래스의 결과를 받을 때사용 |
.thenCombine | ( CompletableFuture 클래스 ,조합식) | CompletableFuture 클래스가 인수로 다른 CompletableFuture 클래스의 결과를 받지만 첫번째 CompletableFuture 클래스의 연산결과를 기다리지 않음 |
.thenAccept | (Consumer<T>) | CompletableFuture의 연산결과를 소비 |
.allOf | ( CompletableFuture 클래스 배열) | CompletableFuture의 연산이 완료되면 CompletableFuture<void> 반환 |