주요글: 도커 시작하기
반응형
셧다운 후크를 사용하여 어플리케이션의 종료를 안전하게 처리하는 것에 대해서 살펴본다.

셧다운 후크 사용하기

자바 어플리케이션을 실행한 후 어플리케이션을 종료할 때 Ctrl+C 키를 눌러서 종료하는 경우가 많을 것이다. 하지만, Ctrl+C 키를 누르게 되면 JVM은 쓰레드들이 어떤 상황에 있는 지에 상관없이 쓰레드를 강제적으로 종료시키기 때문에 안정적으로 어플리케이션의 종료작업을 진행할 수 없을수도 있다. 특히 서버 프로그램의 경우 할당한 자원이나 상태 정보등을 서버 종료시에 올바르게 처리해주어야 하는데, 강제 종료시 이런 것들을 올바르게 처리할 수 없는 문제가 발생한다.

자바는 이런 문제를 방지하기 위해서 1.3 버전부터 '셧다운 후크(Shutdown Hook)'라는 기능을 도입하였다. 셧다운 후크는 JVM이 셧다운될 때에 셧다운 이벤트를 가로채서 어떤 코드를 수행한 후 최종적으로 셧다운 되도록 한다. 참고로, JVM은 다음과 같은 상황인 경우 셧다운 이벤트를 발생시킨다.

  • 정상적으로 종료될 때. 예) 마지막 논데몬 쓰레드가 종료되었거나 System.exit()가 호출될 때.
  • JVM이 강제적으로 종료될 때. 예) 시스템 셧다운, 사용자 로그아웃, Ctrl+C 누름
JVM이 정상적으로 종료될 때 뿐만 아니라 강제적으로 종료될 때 모두 셧다운 후크가 동작하기 때문에 셧다운 후크를 사용하게 되면 어플리케이션의 종료를 올바르게 처리할 수 있게 된다.

셧다운 후크는 Runtime.addShutdownHook(Thread thread) 메소드를 사용하여 지정할 수 있다. addShutdownHook() 메소드는 생성만 되고 아직 시작되지 않은 Thread 객체를 파라미터로 전달받는다. JVM이 셧다운 되면 addShtudownHook() 메소드를 사용하여 등록한 쓰레드의 start() 메소드가 호출되어 쓰레드를 수행하게 된다. 즉, 셧다운 이벤트가 발생하게 되면, addShtudownHook() 메소드를 사용하여 등록한 쓰레드의 run() 메소드가 실행되는 것이다. 따라서 쓰레드의 run() 메소드에서 알맞은 종료 작업을 처리하면 된다.

실제로 셧다운 후크가 어떻게 동작하는 지 살펴보기 위해 다음과 같은 간단한 예제를 작성해보았다.

    public class ShutdownHookTest {
        
        public ShutdownHookTest() {
            Runtime.getRuntime().addShutdownHook(new ShutdownHookThread());
        }
        
        public static void main(String[] args) throws InterruptedException {
            ShutdownHookTest test = new ShutdownHookTest();
            Thread.sleep(10000);
        }
        
        public class ShutdownHookThread extends Thread {
            
            public ShutdownHookThread() {
                
            }
            
            public void run() {
                System.out.println("ShutdownHookThread 실행");
            }
        }
    }

ShutdownHookTest 클래스는 ShutdownHookThread를 셧다운 후크로 등록하며, main() 메소드에서는 ShutdownHookTest 객체를 생성한 후 10초가 쓰레드를 정지하고 있다. 위 프로그램을 실행하면 10초 후에(즉, 정상적으로 JVM이 종료될 때) 다음과 같은 결과가 출력될 것이다.

    C:\eclipse\workspace\JavaCanArticleServer>java ShutdownHookTest
    ShutdownHookThread 실행

이번엔 ShutdownHookTest를 실행한 후, JVM이 정상적으로 종료하기 전에(즉, 10초 이내에) Ctrl+C를 눌러보자. 그러면 다음과 같은 결과가 출력될 것이다.

    C:\eclipse\workspace\JavaCanArticleServer>java ShutdownHookTest
    [Ctrl+C 누름]
    ShutdownHookThread 실행

위의 실행 결과를 보면 정상적으로 종료된 경우와 마찬가지로 비정상 종료가 되더라도 셧다운 후크로 등록한 쓰레드가 시작되는 것을 알 수 있다. Ctrl+C가 아니라 윈도우의 [작업관리자]에서 강제적으로 프로세스를 종료시켜도 역시 셧다웃 후크 쓰레드가 시작된다.

따라서, 어플리케이션 종료시 알맞은 처리를 해주어야 한다면 셧다운 후크 쓰레드를 작성해서 알맞게 run() 메소드를 구현해주면 된다. 실제로 자바 기반의 어플리케이션 서버나 강제 종료에 대응해야 하는 어플리케이션들은 대부분 이 셧다운 후크 기능을 사용하여 강제 종료에 알맞게 대응하고 있다. 예를 들어, 톰캣이나 JBoss와 같은 어플리케이션 서버들이 이 기능을 사용하고 있다.

셧다운 후크 기능 사용시 주의사항

셧다운 후크 기능을 사용할 때는 몇가지 주의할 점이 있다. 첫번째는 셧다운 후크 쓰레드는 매우 중요한 시점에서 수행된다는 점이다. 셧다운 후크 쓰레드는 어플리케이션이 종료되는 순간에 실행되고 특히 비정상적으로 종료될 때에도 실행되기 때문에, 에러 대처와 같은 방어 코드를 완벽하게 작성해야 한다.

두번째로 주의할 점은 셧다운 후크 쓰레드는 최대한 빨리 자신의 기능을 수행해야 한다는 점이다. 어플리케이션이 종료 버튼을 눌렀는데 수십초동안 종료되지 않고 셧다운 후크 쓰레드가 실행된다면 사용자들은 짜증을 낼 것이다. 또한 강제적인 종료나 시스템 셧다운 시에 운영체제는 어플리케이션이 수십초 내에 종료하지 않을 경우 강제적으로 프로세스를 죽인다. 따라서 셧다운 후크 쓰레드는 최대한 빠른 시간 내에 어플리케이션의 종료 작업을 마무리해야 한다.

관련링크:

+ Recent posts