Search

자바에서 멀티 쓰레드 사용하기 2

태그
Java
면접질문
작성 상태
작성 완료
작성일
2023/12/07
참고 링크
참고 링크 2
약 1년전 공부하다가 도저히 이해가 안가던 부분을 이제는 이해할 수 있게 되어 포스팅을 이어 작성한다.

Java 8 : Future 의 Stream 버전, CompletableFuture

java 1.5에서의 멀티 쓰레드 프로그래밍 다시 보기

java 1.5에서는 Executor, ExecutorService, ScheduledExecutorService, Executors, Future, Callable 을 이용해 보다 더 추상화된 방법으로 멀티 쓰레드 프로그래밍을 할 수 있다.
Future는 비동기 요청의 응답을 추상화한 인터페이스다! 비동기 요청의 응답이 완료여부 조회, 비동기 요청의 취소, 비동기 요청의 응답 조회 기능이 정의되어 있다.
이를 사용하기 위해서는 ExecutorService 를 사용해야 한다. 즉, Java 1.5 에서 추가된 새로운 멀티 쓰레드 프로그래밍은 다음과 같은 방법으로 수행된다.
이들의 사용 방식은 다음과 같다.
1.
Executors 를 이용해 적절한 ExecutorService 구현체 인스턴스를 가져온다.
2.
Callable 혹은 Runnable 의 구현체를 ExecutorService 의 각종 메서드의 매개변수로 사용하여 Future 인스턴스를 얻는다.
3.
비동기로 실행한 작업의 결과가 필요할 경우 Future 의 인스턴스의 get()을 이용해 결과를 얻는다.

문제점

1.
Future.get() 은 블로킹 방식으로 동작한다. 따라서, 해당 작업이 오랜 시간 걸리는 경우, 이를 기다리는 동안 다른 작업을 할 수 없다. 논 블로킹 방식으로 동작할 수 있는 것이 있다면, 미리 콜백 함수를 등록하고 비동기 작업이 완료된 경우 이를 알아서 수행하도록 하면 더 좋을 것이다.
2.
작업을 Future 외부에서 종료시킬 방법이 없다.
3.
여러 비동기 작업이 연쇄적으로 일어나는 체인을 구성하기 힘들다. 예를 들어, 게시글을 가져오는 것이 성공한 경우, 댓글을 가져오는 작업을 수행하게 하려면 ExecutorService 를 한 번 더 사용해야 한다.
4.
작업에 예외가 발생할 경우를 처리하기 위한 별도의 API가 없다.

CompletableFuture

CompletableFuture 는 이런 문제를 해결하기 위해 java 1.8에 추가되었다. java 1.8에서는 함수형 프로그래밍이 도입되었고, 이 클래스도 이를 적극 활용할 수 있도록 제작되어있다.
CompleteFuture 는 기존의 Future가 ExecutorService 를 통해서 생성되었던 것과 달리, CompleteFuture 의 정적 팩토리 메서드를 사용해 생성할 수 있다. 매개변수로 ExecutorService 의 구현체를 함께 전달하면 해당 쓰레드풀을 이용해 작업을 수행할 수 있다.
CompleteFuture 의 여러 메서드들이 CompleteFuture 인스턴스를 반환하기 때문에 메서드 체이닝 기법을 이용해 마치 Stream 처럼 CompleteFuture 를 사용할 수 있다.

콜백 등록

1.
thenApply : Function 인터페이스를 사용해 비동기 작업의 결과를 다른 것으로 변환한다.
2.
thenAccept : Consumer 인터페이스를 사용해 비동기 작업의 결과를 사용한다.
3.
thenRun : Runnable 인터페이스를 사용해 비동기 작업의 결과와 무관한 다른 작업을 수행한다.
각 메서드에는 Async 접미사가 붙은 메서드가 또 있는데, 이를 사용하면 콜백이 다른 쓰레드에서 실행되게 된다. 이때, Executor 를 추가로 전달하면 별도의 쓰레드 풀의 쓰레드를 사용하게 할 수 도 있다.

작업 조합

1.
thenCompose : Function 인터페이스를 사용해 비동기 작업의 결과를 사용해 또 다른 비동기 작업을 수행한다.
2.
thenCombine : 두개의 작업을 각각 독립적으로 수행한 뒤, 두 작업의 결과를 이용해 콜백 함수를 수행한다.

예외 처리

1.
exceptionally : 예외를 처리한다. Function<Throwable, ? extends T> 를 매개변수로 받는다.
2.
handle : 결과와 예외를 모두 받아 처리한다.