Runnable 인터페이스의 run() 메서드를 구현할 때 "InterruptedException" 체크 예외를 밖으로 던질 수 없는 이유를 알아보자.
Runnable 인터페이스
public interface Runnable {
void run();
}
자바에서 메서드를 재정의 할 때, 재정의 메서드가 지켜야 할 예외와 관련된 규칙이 있다.
- 체크 예외
- 부모 메서드가 체크 예외를 던지지 않는 경우, 재정의된 자식 메서드도 체크 예외를 던질 수 없다.
- 자식 메서드는 부모 메서드가 던질 수 있는 체크 예외의 하위 타입만 던질 수 있다.
- 언체크(런타임) 예외
- 예외 처리를 강제하지 않으므로 상관없이 던질 수 있다.
Runnable 인터페이스의 run() 메서드는 아무런 체크 예외를 던지지 않는다. 따라서 Runnable 인터페이스의
run() 메서드를 재정의 하는 곳에서는 체크 예외를 밖으로 던질 수 없다.
잘못된 코드 예시

- main()은 체크 예외를 밖으로 던질 수 있다.
- run()은 체크 예외를 밖으로 던질 수 없다.
예를 들어 다음 코드의 `InterruptedException` 도 체크 예외이므로 던질 수 없다. 컴파일 오류가 발생한다.
static class MyRunnable implements Runnable {
public void run() throws InterruptedException {
Thread.sleep(3000);
}
}
체크 예외 제약 사항을 둔 이유
부모 클래스의 메서드를 호출하는 클라이언트 코드는 부모 메서드가 던지는 특정 예외만을 처리하도록 작성된다. 자식 클래스가 더 넓은 범위의 예외를 던지면 해당 코드는 모든 예외를 제대로 처리하지 못할 수 있다. 이는 예외 처리의 일관성을 해치고, 예상하지 못한 런타임 오류를 초래할 수 있다.
실제 동작하는 코드는 X
class Parent {
void method() throws InterruptedException {
// ...
}
}
class Child extends Parent {
@Override
void method() throws Exception {
// ...
}
}
public class Test {
public static void main(String[] args) {
Parent p = new Child();
try {
p.method();
} catch (InterruptedException e) {
// InterruptedException 처리
}
}
}
- 자바 컴파일러는 "Parent p"의 method()를 호출한 것으로 인지한다.
- "Parent p"는 "InterruptedException" 를 반환하는데, 그 자식이 전혀 다른 예외를 반환한다면 클라이언트는 해당 예외를 잡을 수 없다. 이것은 확실하게 모든 예외를 체크하는 체크 예외의 규약에 맞지 않는다.
- 따라서 자바에서 체크 예외의 메서드 재정의는 다음과 같은 규칙을 가진다.
체크 예외 재정의 규칙
자식 클래스에 재정의된 메서드는 부모 메서드가 던질 수 있는 체크 예외의 하위 타입만을 던질 수 있다.
원래 메서드가 체크 예외를 던지지 않는 경우, 재정의된 메서드도 체크 예외를 던질 수 없다.
안전한 예외 처리
체크 예외를 run() 메서드에서 던질 수 없도록 강제함으로써, 개발자는 반드시 체크 예외를 try-catch 블록 내에서 처리하게 된다.
이는 예외 발생 시 예외가 적절히 처리되지 않아서 프로그램이 비정상 종료되는 상황을 방지할 수 있다. 특히 멀티스레딩 환경에서는 예외 처리를 강제함으로써 스레드의 안정성과 일관성을 유지할 수 있다.
체크 예외를 강제하는 이런 부분들은 자바 초창기 기조이고, 최근에는 체크 예외보다는 언체크(런타임) 예외를 선호한다.
Sleep 유틸리티 작성하기
기존 코드
void run() {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
- 매번 try-catch로 감싸는 것이 매우 불편하다.
ThreadUtils.sleep()

- Sleep 함수에서 "RuntimeException"을 발생시키도록 변경하여 더 이상 sleep 함수 호출 시, Try-catch를 사용하지 않도록 한다.
'멀티스레드와 동시성' 카테고리의 다른 글
| Ch04. 스레드 제어와 생명 주기2 - 인터럽트 (0) | 2024.08.06 |
|---|---|
| Ch03. 스레드 제어와 생명 주기 - Join (0) | 2024.08.04 |
| Ch03. 스레드 제어와 생명 주기 - 설명 / 코드 (0) | 2024.08.02 |
| Ch03. 스레드 제어와 생명 주기 - 스레드 기본 정보 (0) | 2024.08.02 |
| Ch02. 스레드 생성과 실행 -Runnable을 만드는 다양한 방법 (0) | 2024.08.01 |