자바에서 비동기 처리 시 예외 처리 (try-catch)
자바에서 비동기 처리(Asynchronous Processing) 를 할 때 예외(Exception)를 적절하게 처리하는 것은 매우 중요함.
비동기 코드에서는 기존의 try-catch 문이 제대로 동작하지 않을 수 있기 때문에 별도의 예외 처리 방식을 적용해야 함.
1️⃣ 기본적인 try-catch 블록 (동기 코드에서 예외 처리)
동기(Synchronous) 코드에서는 try-catch 블록을 사용하여 예외를 쉽게 처리할 수 있음.
public class SyncTryCatchExample {
public static void main(String[] args) {
try {
int result = 10 / 0; // 예외 발생 (ArithmeticException)
System.out.println(result);
} catch (ArithmeticException e) {
System.out.println("예외 발생: " + e.getMessage());
}
}
}
출력:
예외 발생: / by zero
이처럼 동기 코드에서는 try-catch를 사용하면 문제없이 예외를 처리할 수 있음.
2️⃣ 비동기(멀티스레드) 코드에서 try-catch 문제점
비동기적으로 실행되는 코드에서는 try-catch가 즉시 예외를 잡지 못할 수 있음.
예제: Thread 내부에서 try-catch 없이 예외 발생
public class AsyncExceptionExample {
public static void main(String[] args) {
Thread thread = new Thread(() -> {
int result = 10 / 0; // ArithmeticException 발생
System.out.println("비동기 결과: " + result);
});
thread.start();
System.out.println("메인 스레드는 계속 실행됨");
}
}
출력 결과:
메인 스레드는 계속 실행됨
Exception in thread "Thread-0" java.lang.ArithmeticException: / by zero
문제점:
• 예외가 발생해도 try-catch가 없으므로 스레드가 죽어버림.
• 메인 스레드에는 영향을 주지 않지만, Thread 내부에서 예외를 잡지 않으면 해당 예외가 처리되지 않음.
3️⃣ 비동기 코드에서 try-catch로 예외 처리하는 방법
비동기 코드에서 예외를 잡으려면 try-catch를 비동기 실행 블록 내부에 직접 추가해야 함.
✅ Thread 내부에서 try-catch 적용
public class AsyncTryCatchExample {
public static void main(String[] args) {
Thread thread = new Thread(() -> {
try {
int result = 10 / 0; // 예외 발생
System.out.println("비동기 결과: " + result);
} catch (ArithmeticException e) {
System.out.println("비동기 예외 발생: " + e.getMessage());
}
});
thread.start();
System.out.println("메인 스레드는 계속 실행됨");
}
}
출력 결과:
메인 스레드는 계속 실행됨
비동기 예외 발생: / by zero
✅ 해결됨!
비동기 코드 내부에 try-catch를 추가하면 예외가 발생하더라도 정상적으로 잡을 수 있음.
4️⃣ ExecutorService를 사용할 때 예외 처리
❌ ExecutorService에서 try-catch 없이 예외 발생 시 문제점
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ExecutorWithoutTryCatch {
public static void main(String[] args) {
ExecutorService executor = Executors.newSingleThreadExecutor();
executor.submit(() -> {
int result = 10 / 0; // 예외 발생
System.out.println("비동기 결과: " + result);
});
executor.shutdown();
}
}
출력 결과:
Exception in thread "pool-1-thread-1" java.lang.ArithmeticException: / by zero
submit()을 사용하면 예외가 내부적으로 처리되지 않고 조용히 무시될 수도 있음.
✅ ExecutorService에서 예외 처리하는 방법 ① (try-catch 사용)
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ExecutorTryCatch {
public static void main(String[] args) {
ExecutorService executor = Executors.newSingleThreadExecutor();
executor.submit(() -> {
try {
int result = 10 / 0; // 예외 발생
System.out.println("비동기 결과: " + result);
} catch (ArithmeticException e) {
System.out.println("비동기 예외 발생: " + e.getMessage());
}
});
executor.shutdown();
}
}
✅ 정상적으로 예외 처리 가능!
출력 결과:
비동기 예외 발생: / by zero
✅ ExecutorService에서 예외 처리하는 방법 ② (Future 사용)
Future를 사용하면 작업의 결과를 받아 예외를 처리할 수 있음.
import java.util.concurrent.*;
public class ExecutorFutureExample {
public static void main(String[] args) {
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<Integer> future = executor.submit(() -> {
return 10 / 0; // 예외 발생
});
try {
int result = future.get(); // 여기서 예외가 발생함
System.out.println("비동기 결과: " + result);
} catch (InterruptedException | ExecutionException e) {
System.out.println("Future 예외 발생: " + e.getCause());
}
executor.shutdown();
}
}
출력 결과:
Future 예외 발생: java.lang.ArithmeticException: / by zero
✅ get() 호출 시 예외가 발생하므로 try-catch로 잡아야 함.
5️⃣ CompletableFuture에서 예외 처리
✅ exceptionally() 메서드를 사용한 예외 처리
import java.util.concurrent.CompletableFuture;
public class CompletableFutureExample {
public static void main(String[] args) {
CompletableFuture.supplyAsync(() -> {
return 10 / 0; // 예외 발생
}).exceptionally(ex -> {
System.out.println("CompletableFuture 예외 발생: " + ex.getMessage());
return 0; // 기본값 반환
}).thenAccept(result -> System.out.println("결과: " + result));
// 메인 스레드 종료 방지
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
출력 결과:
CompletableFuture 예외 발생: / by zero
결과: 0
✅ exceptionally() 메서드를 사용하면 예외를 잡고 기본값을 반환할 수 있음.
6️⃣ 정리하면:
• Thread 내부에서는 반드시 try-catch를 직접 사용해야 예외를 잡을 수 있음.
• ExecutorService.submit()은 예외를 조용히 무시할 수 있음 → Future.get()에서 예외를 확인해야 함.
• CompletableFuture는 exceptionally()를 사용하여 비동기 예외를 처리하는 것이 가장 안전함.
출처 : ChatGPT
'BE > Java' 카테고리의 다른 글
[Java] ArrayDeque (0) | 2025.04.02 |
---|---|
[Java] 체인호출 (0) | 2025.03.24 |
[Java] File I/O (0) | 2025.03.18 |
[Java] BufferedReader (0) | 2025.03.17 |
[Java] StringTokenizer (0) | 2025.03.16 |