티스토리 뷰
자바에는 UncaughtExceptionHandler 라는 인터페이스가 있다. 생소한 인터페이스일텐데 jdk 1.5 에 추가된 인터페이스이다. Thread 클래스의 내부 인터페이스로 선언되어있는데, 위치만 봐도 알 수 있듯이 쓰레드에 관련한 인터페이스이다. 쓰레드가 동작할때 내부에서 발생한 예외를 처리하지 않을 경우 UncaughtExceptionHandler 인터페이스의 구현체에서 예외를 처리할 수 있다.
@FunctionalInterface
public interface UncaughtExceptionHandler {
/**
* Method invoked when the given thread terminates due to the
* given uncaught exception.
* <p>Any exception thrown by this method will be ignored by the
* Java Virtual Machine.
* @param t the thread
* @param e the exception
*/
void uncaughtException(Thread t, Throwable e);
}
함수형 인터페이스로 매우 단순한 형태이다. 예외를 처리할 쓰레드와, 발생한 예외를 파라미터로 받는다. 어떤식으로 구성할 수 있는지 확인해보자.
public static void main(String[] args) {
Thread.UncaughtExceptionHandler handler = (t, e) -> {
System.out.println("thread :: " + t.getName() + " exception :: " + e);
};
Thread t = new Thread(() -> {
for(int i = 0; i < 100; i++) {
System.out.println("hello thread");
}
throw new RuntimeException();
});
t.setUncaughtExceptionHandler(handler);
t.start();
}
람다를 이용해 UncaughtExceptionHandler 를 구현했다. 그리고 추가 쓰레드를 하나 생성하고, 해당 쓰레드에 핸들러를 등록해줬다.
Runnable 람다를 보면 for 문 바깥에 RuntimeException 을 일으키게되어있는데, 우리가 구현한 인터페이스는 말 그대로 예외 핸들러이기때문에 쓰레드 내에서 예외가 발생하지 않을 경우 해당 구현체는 작동하지 않는다. 구현체의 동작을 확인하기 위해 강제로 예외를 일으켰다.
코드를 실행해보면 잘 돌아가는걸 확인 할 수 있다. 하지만 Thread 객체를 직접 생성하는건 그다지 권장하는 방식이 아니다. Executor 를 이용하는 코드를 확인해보자.
public static void main(String[] args) {
Thread.UncaughtExceptionHandler handler = (t, e) -> {
System.out.println("thread :: " + t.getName() + " exception :: " + e);
};
ExecutorService executorService = Executors.newCachedThreadPool(new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
Thread thread = Executors.defaultThreadFactory().newThread(r);
thread.setUncaughtExceptionHandler(handler);
return thread;
}
});
executorService.execute(() -> {
for(int i = 0; i < 100; i++) {
System.out.println("hello thread");
}
throw new RuntimeException();
});
executorService.shutdown();
}
Executors 에 정의된 팩토리 메서드는 ThreadFactory 라는 인터페이스를 선택 인자로 받고있다. ThreadFactory 자체도 람다로 구현할 수 있지만 지금은 타입을 좀 더 확인하기 쉽게 익명 클래스로 작성했다. ThreadFactory 인터페이스가 Thread 를 리턴해야 하기 때문에 해당 메서드 내에서 핸들러를 등록할 수 있다. 나는 defaultThreadFactory 를 이용했지만 저 코드에서 new Thread 를 해도 무방하다.
사실 앞으로도 쓸 일이 많을 것 같지는 않다. 하지만 필요할때 요긴하게 써먹을 수 있도록 남겨놓는다.
'Java' 카테고리의 다른 글
builder pattern 에 대한 고찰 (3) | 2022.04.23 |
---|---|
ThreadPoolExecutor 사용시 maximumPoolSize 동작방식 (5) | 2021.02.02 |
동기화 방법에 따른 데드락 상태에서 스레드 덤프 차이 (0) | 2020.03.29 |
동기화 클래스 사용하기(CountDownLatch, Semaphore, CyclicBarrier) (0) | 2020.03.05 |
JDK 14 Release note (0) | 2020.02.07 |
- Total
- Today
- Yesterday
- code
- 정규표현식
- programming
- http
- generics
- javascript
- Kotlin
- backend개발환경
- servlet
- Git
- JavaScript Core
- OOP
- DesignPattern
- mariadb
- JPA
- frontend개발환경
- TEST
- spring cloud
- java
- frontcode
- clean code
- Jackson
- Design Pattern
- toby
- Spring
- go-core
- db
- EffectiveJava
- MySQL
- java8
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 | 31 |