본문 바로가기
Language/Java

[JAVA] finally 블록이 실행되지 않는 예외적인 4가지 시나리오 분석

by Papa Martino V 2026. 1. 20.
728x90

finally 블록
finally 블록

 

자바 프로그래밍을 처음 배울 때 우리는 "finally 블록은 예외 발생 여부와 상관없이 무조건 실행된다"고 배웁니다. 하지만 시니어 개발자로 거듭나기 위해서는 이 '무조건'이라는 단어 뒤에 숨겨진 예외 상황들을 정확히 파악하고 있어야 합니다. 시스템의 안정성을 설계할 때 finally에만 의존했다가 자원이 해제되지 않는 치명적인 버그를 마주할 수 있기 때문입니다. 오늘 포스팅에서는 자바 가상 머신(JVM)의 동작 원리를 바탕으로, finally 블록이 실행되지 않는 아주 특별하고 구체적인 사례들을 정리해 보겠습니다.

1. finally 블록의 일반적인 메커니즘

일반적으로 finally는 리소스 반납(파일 클로즈, DB 연결 종료 등)을 보장하기 위해 사용됩니다. try 블록에서 return이 발생하더라도 JVM은 해당 메서드를 완전히 빠져나가기 직전에 finally 코드를 수행합니다.

2. finally가 실행되지 않는 4가지 절대적 시나리오

자바 명세(JLS)와 JVM의 물리적 한계로 인해 finally가 호출되지 않는 상황은 다음과 같습니다.

① System.exit() 호출

try 혹은 catch 블록 내부에서 System.exit(int status)가 호출되면 JVM 프로세스 자체가 즉시 종료됩니다. 이 경우 JVM은 더 이상 코드를 실행할 수 있는 상태가 아니므로 finally 블록은 무시됩니다.

② 무한 루프와 데드락(Deadlock)

try 블록 내에서 무한 루프가 발생하거나, 스레드가 데드락 상태에 빠져 제어권을 반환하지 못하면 프로세스가 해당 지점에 머물게 됩니다. 당연히 finally 구문까지 도달하지 못하므로 실행될 기회를 얻지 못합니다.

③ 외부 프로세스에 의한 강제 종료 (Kill signal)

운영체제 단에서 kill -9 명령어로 JVM 프로세스를 강제로 종료하거나, 정전 등으로 하드웨어가 멈추는 경우입니다. 소프트웨어적인 보장 범위를 벗어난 시나리오입니다.

④ JVM 크래시 (Fatal Error)

JVM 자체의 버그나 하드웨어 결함으로 인해 VirtualMachineError 중에서도 심각한 레벨의 에러가 발생하여 런타임 환경이 파괴될 때 발생합니다.

3. 주요 상황별 비교 요약

개발자가 제어할 수 있는 영역과 없는 영역을 구분하여 정리한 표입니다.

상황 구분 실행 여부 상세 이유
return 문 실행 실행됨 메서드 종료 전 JVM이 스택을 정리하며 호출함
System.exit() 실행 안 됨 JVM 프로세스가 즉각 중단됨
스레드 인터럽트/데드락 실행 안 됨 제어권이 finally 블록으로 넘어오지 못함
Background Thread 종료 실행 안 됨 데몬 스레드인 경우 메인 스레드 종료 시 즉시 종료

4. Sample Example: 실무에서 주의해야 할 패턴

잘못된 예: 데몬 스레드에서의 자원 해제

Thread t = new Thread(() -> {
    try {
        System.out.println("작업 중...");
        Thread.sleep(10000);
    } finally {
        System.out.println("이 문구는 출력되지 않을 수 있습니다.");
    }
});
t.setDaemon(true); // 데몬 스레드로 설정
t.start();
// 메인 스레드가 즉시 종료되면 위 finally는 실행되지 않음
    

5. 독창적인 결론: try-with-resources의 권장

위와 같은 finally의 한계를 보완하고 코드를 깔끔하게 유지하기 위해 Java 7부터는 try-with-resources 구문을 권장합니다. AutoCloseable 인터페이스를 구현한 객체를 사용하면 수동으로 finally를 작성하는 번거로움과 실수를 줄일 수 있습니다. 비록 JVM이 비정상 종료되는 상황까지 막을 수는 없지만, System.exit()와 같은 안티 패턴을 피하고 적절한 타임아웃 설정을 통해 finally가 실행될 수 있는 환경을 보장하는 것이 중요합니다.


내용 출처:
- Java Language Specification (JLS) SE 17 Edition, Section 14.20.2
- Oracle Java Documentation: The finally Block
- Effective Java 3rd Edition (Joshua Bloch) - Item 9: Prefer try-with-resources to try-finally

728x90