일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- 서비스 디스커버리
- 도커
- docker-compose
- 플로이드 와샬
- spring boot
- 메모이제이션
- 스택
- 비트마스킹
- 달팽이
- spring cloud
- 구간 트리
- 이분 매칭
- 백트래킹
- BFS
- 게이트웨이
- 다익스트라
- Gradle
- Zuul
- 주울
- 유레카
- 구현
- dp
- 완전 탐색
- Java
- 이분 탐색
- Spring Cloud Config
- ZuulFilter
- 트리
- Logback
- 스프링 시큐리티
- Today
- Total
Hello, Freakin world!
[Java] CompletableFuture를 이용해 비동기 예외 처리하기 본문
비동기 예외 처리?
상황을 자세히 살펴보자.
스레드 A,B가 있다고 하자. A는 호출자 스레드이고 A스레드에서 어떤 작업을 B로 위임했다.
B 작업의 결과를 참조하기 위해 우리는 자바에서 지원하는 동시성 api를 사용했고
그 결과는 Future를 통해 접근할 수 있다고 하자.
예제 코드
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class ThreadA {
public static void main(String[] args) throws ExecutionException, InterruptedException {
ExecutorService executorService = Executors.newCachedThreadPool();
Task task = new Task();
Future future = executorService.submit(task::doSomething);
future.get();
System.out.println("main 종료");
}
}
class Task {
public void doSomething() {
throw new RuntimeException("");
}
}
다른 스레드(ThreadB)에 task를 위임했을 때, 예외를 던지도록 해보자.
이 경우 예외는 호출자 스레드까지 전파되는데, 이는 get 메서드 명세를 보면 알 수 있다.
1. java.util.concurrent.CancellationException – if the computation was cancelled
2. java.util.concurrent.ExecutionException – if the computation threw an exception
3. InterruptedException – if the current thread was interrupted while waiting
위의 예제에서는 RuntimeException이 2번에 해당되기 때문에 ExecutionException 를 던진다.
하지만 만약 예외없이 무한정 대기해야되는 상황이 오면 어떨까?
이 경우 오버로드된 get 메서드를 이용해 타임아웃을 지정해 줄 수 있다. 시간이 다됐을 경우 TimeoutException 을 던지게 되고 이를 처리하면 된다.
하지만 이 경우 ThreadB에서 무슨 일이 일어난건지는 알 수가 없다. 그냥 단순히 시간초과에 의한 TimeoutException를 받을 뿐이다. 여기서 CompletableFuture를 사용하면 ThreadB 내부의 예외를 호출자 스레드에 전달할 수 있다.
예제 코드
public class ThreadA {
public static void main(String[] args) throws ExecutionException, InterruptedException {
Task task = new Task();
Future<String> future = task.doSomething();
System.out.println(future.get());
System.out.println("main 종료");
}
}
class Task {
public Future<String> doSomething() {
CompletableFuture<String> requestFuture = new CompletableFuture<>();
new Thread(() -> {
try{
requestFuture.complete("hello, world!");
}catch (Exception ex) {
requestFuture.completeExceptionally(ex); // 도중에 문제가 발생하면 에러를 포함시켜 Future 종료.
}
}).start();
return requestFuture;
}
}
completeExceptionally 메서드를 통해 내부의 예외를 future 객체에 전달하는 것을 볼 수 있다.
위의 doSomething는 팩토리 메서드에 의해 다음으로 대체될 수 있다.
public Future<String> doSomething() {
return CompletableFuture.supplyAsync(() -> "Hello, world!");
}
참고자료
자바 8 in action - 라울-게이브리얼 우르마, 마리오 푸스코, 앨런 마이크로프트 지음
'프로그래밍 언어 > Java' 카테고리의 다른 글
[Java] 정규표현식 핵심만 알고 간단하게 사용하자 (0) | 2020.03.30 |
---|---|
[Java] ServerSocket(Channel) 동기방식의 accept 동작 방식 (0) | 2020.03.19 |
[Java] Future 에 대해서 간단하게 정리 (0) | 2020.03.16 |
[Java][NIO] channel 객체를 Selector 객체에 등록하는 경우 (0) | 2020.03.14 |
[Java][Gson] Gson 라이브러리 메모 (0) | 2020.03.10 |