
✅ 1. Runtime.addShutdownHook()
Runtime.addShutdownHook()는 자바 애플리케이션이 종료될 때 실행할 코드를 등록하는 메서드이다. 이를 활용하면 프로그램이 종료되기 직전에 특정 작업(파일 저장, 리소스 정리 등)을 수행할 수 있다.
✅ 2. JVM 종료 이벤트란?
여기서 정상 또는 비정상 종료의 정의는 명세서에 나와 있다. 자바의 가상 머신은 두 가지 종류의 이벤트를 받아 종료한다.
정상 종료
- 프로그램이 정상적으로 종료될 때
- System.exit()가 호출될 때
비정상 종료
- Ctrl + C(사용자 인터럽트)
- 사용자 로그오프 또는 시스템 종료 등 시스템 이벤트
⚠️ 하지만 아래와 같은 경우에는 실행되지 않을 수 있다.
- kill -9 (강제 종료)
- OutOfMemoryError 발생
📌 정리하자면
- 프로그램이 정상 종료되거나, Ctrl + C 같은 신호로 종료될 때 실행됨
- System.exit()가 호출되거나, JVM이 정상 종료될 때도 실행됨
- 하지만 kill -9(강제 종료) 또는 OutOfMemoryError 같은 예외 상황에서는 실행되지 않을 수도 있음
✅ 3. 코드 흐름
public class ShutdownHookExample {
public static void main(String[] args) {
// 종료 훅 등록
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
System.out.println("프로그램이 종료되기 전에 실행할 작업");
}));
System.out.println("프로그램 실행 중...");
try {
Thread.sleep(5000); // 5초 동안 실행 유지
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("프로그램 종료");
}
}
💡 실행 결과 (콘솔▼)
프로그램 실행 중...
프로그램 종료
프로그램이 종료되기 전에 실행할 작업
JVM이 종료되기 직전에 미리 등록한 코드(Shutdown Hook)가 종료 후 실행되는 것을 콘솔에서 확인 가능하다.
✅ 4. 언제 써?
- 파일 저장 또는 로그 기록: 프로그램이 종료되기 전에 데이터를 저장할 때
- 리소스 정리 (예: 데이터베이스 연결 해제) :실행 중이던 프로세스를 정리 할 때 유용함
- 서버 애플리케이션에서 클린업 작업 수행: 웹 서버가 종료시 특정 정리 작업을 수행 가능
✅ 사용 예제
public class ShutdownHookTest {
// HookThread는 Thread 클래스를 상속받아 run() 메서드를 오버라이드한 스레드이다.
// 이 스레드는 JVM 이 종료될 때 실행하고, 실행시 "Hook Run"을 출력한다.
static class HookThread extends Thread {
@Override
public void run() {
System.out.println("Hook Run");
}
}
public static void main(String[] args) {
// JVM 종료 시 실행될 Shutdown Hook 등록
// Runtime.getRuntime()을 통해 Runtime 객체 가져오기
// addShutdownHook()을 호출하여 HookThread를 등록한다
Runtime.getRuntime().addShutdownHook(new HookThread());
System.out.println("End");
}
}
메인에서 "End"를 출력한 후 프로그램이 종료된다. JVM 종료시 Shutdown Hook이 실행된다.
📌 아래처럼 예외가 발생하면?
“End”는 출력되지 않지만 “Hook Run”이 출력된다.
// ...
public static void main(String[] args) {
Runtime.getRuntime().addShutdownHook(new HookThread());
int errorNum = 1 / 0;
System.out.println("End");
}
}
Exception in thread "main" java.lang.ArithmeticException: / by zero
at ShutdownHookTest.main(ShutdownHookTest.java:10)
Hook Run
📌 콘솔에서 sleep 동안 인터럽트(Ctrl+C)를 주는 경우
“End”는 출력되지 않지만 “hook Run”이 출력된다.
// ...
public static void main(String[] args) {
Runtime.getRuntime().addShutdownHook(new HookThread());
try {
System.out.println("sleep 3s");
Thread.sleep(3000);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("End");
}
}
sleep 3s
End
Hook Run
메인에서 일어나는 일
- 먼저 "sleep 3s" 출력된다.
- Thread.sleep(3000); → 3초 동안 대기 (프로그램이 바로 종료되지 않도록)
- 만약 Thread.sleep() 중 인터럽트가 발생하면 예외 처리
- "End"를 출력한 후 프로그램이 종료됨
- JVM이 종료되면서 Shutdown Hook 실행됨 → Hook Run 출력
⭐ 순서를 지정할 수 없음❌
다중 스레드 실행처럼 여러 개의 Hook이 있을 경우 실행 순서는 정해져 있지 않다. JVM은 Hook 쓰레드를 등록된 순서대로 실행한다고 보장하지 않기 때문에, 두 쓰레드가 어떤 순서로 실행될지는 JVM에 따라 달라질 수 있다.
public class ShutdownHookTest {
static class HookThread extends Thread {
@Override
public void run() {
System.out.println("Hook Run1");
}
}
static class HookThread2 extends Thread {
@Override
public void run() {
System.out.println("Hook Run2");
}
}
public static void main(String[] args) {
Runtime.getRuntime().addShutdownHook(new HookThread());
Runtime.getRuntime().addShutdownHook(new HookThread2());
System.out.println("End");
}
}
첫 번째 실행 결과
End
Hook Run1
Hook Run2
두번째 실행 결과
End
Hook Run2
Hook Run1
⭐ 등록된 Shutdown Hook 실행 차단 🙅🏻♀️
사용할 일이 별로 없을 것 같지만, Runtime.halt(int)를 사용하면 등록된 Shutdown Hook을 실행하지 않고 종료된다.
만약 종료 중에 Halt가 호출될 경우 (종료 중이라면 등록된 Shutdown Hook 쓰레드들이 동시에 실행되는 상태) 실행 중인 Hook이 마칠 떄까지 대기하지 않고, 종료한다.
아래 예제를 보면 종료되기 전에 halt() 메소드를 호출하였으므로 등록된 Hook이 실행되지 않는다.
public class ShutdownHookTest {
static class HookThread extends Thread {
@Override
public void run() {
System.out.println("Hook Run1");
}
}
static class HookThread2 extends Thread {
@Override
public void run() {
System.out.println("Hook Run2");
}
}
public static void main(String[] args) {
// Shutdown Hook 등록
Runtime.getRuntime().addShutdownHook(new HookThread());
Runtime.getRuntime().addShutdownHook(new HookThread2());
System.out.println("End");
// JVM을 강제로 종료
Runtime.getRuntime().halt(0);
}
}
🔥halt(0)의 역할
Runtime.getRuntime().halt(0)은 JVM을 강제로 종료시키는 메서드이다. halt() 메서드는 정상적인 종료 절차를 따르지 않기 때문에, Shutdown Hook이 실행되지 않는다.
- halt()는 JVM이 종료되는 즉시 모든 후속 작업을 중단하고 종료한다.
- 따라서, halt()를 호출하면 등록된 Shutdown Hook은 실행되지 않는다.
📌 halt(0) 호출 전후의 차이
정상적인 종료 (System.exit() 등)에서는 JVM이 종료되기 전에 Shutdown Hook이 실행된다.
End
Hook Run1
Hook Run2
하지만 halt(0) 호출 시, halt(0)은 즉시 JVM을 종료시키기 때문에, Shutdown Hook은 실행되지 않는다.
End
⭐ Shutdown Hook이 실행되면, Hook을 추가, 삭제할 수 없음❌
Shutdown Hook의 동작에 대한 제약이 있는데, Shutdown Hook이 실행되기 시작하면 그 시점에 더 이상 새로운 Shutdown Hook을 추가하거나 기존의 Shutdown Hook을 삭제할 수 없다.
삭제 메서드 Runtime.removeShutdownHook()
만약 시도한다면? IllegalStateException 예외가 발생한다.
아래 예제는 예외가 발생하는 경우이다. Shutdown Hook에 추가한 Hook Thread에 새로운 Hook을 추가하였다. 따라서 종료되면서 IllegalStateException 예외가 발생한다.
public class ShutdownHookTest {
static class HookThread extends Thread {
@Override
public void run() {
Runtime.getRuntime().addShutdownHook(new HookThread());
System.out.println("Hook Run1");
}
}
// ...
}
⚠️ Runtime.addShutdownHook() 사용 시 유의사항
✔️ 스레드는 어렵다
- Shutdown Hook 은 별도의 스레드에서 실행되므로, 원하는 대로 동작하지 않을 수 있음
- 스레드 동작을 예상하기 어렵고, 디버깅이 까다로울 수 있음
✔️ 동시에 실행되므로 thread-safe 하게 작성할 것!
- 프로그램이 종료될 때, 등록된 모든 Shutdown Hook 쓰레드가 동시에 실행됨
- 다른 쓰레드들도 실행 중일 가능성이 있으므로, 데드락(Deadlock) 발생 가능성을 고려해야 함
- 공유 자원(파일, DB 등)에 접근할 때는 동기화(synchronization)를 신경 써야 함
✔️ 무조건 실행된다는 보장이 없음
- `kill -9`(강제 종료) 또는 `OutOfMemoryError` 발생 시 실행되지 않을 수도 있음
- 따라서 Shutdown Hook을 100% 신뢰하면 안 됨!
- 중요한 작업은 별도로 종료 메서드(cleanup method)를 구현하는 것이 안전함
✔️ Hook 쓰레드에서 너무 많은 시간을 소모하면 안 됨
- 시스템 종료 중에 `Shutdown Hook`이 실행되는데, 너무 오래 걸리면 시스템이 무시하고 강제 종료할 수 있음
- 따라서, 최소한의 작업만 수행하는 것이 바람직하다
'프로그래밍언어 > Java' 카테고리의 다른 글
[Java] 자바 소켓 통신 Gson + BufferedWriter 사용중 host 에러 해결법 (11) | 2025.02.10 |
---|---|
[Eclipse] 내가 보려고 만든 이클립스 유용한 단축키 (12) | 2025.02.05 |
[Java] 자바 배열 정렬 할 때 오버플로우 방지하는 법 (11) | 2025.02.01 |
[Spring] 스프링 Spring MVC 흐름 완벽 정리: 초보자도 이해하는 MVC 패턴 (19) | 2025.01.28 |
[JSP & Servlet] URL 매핑 (9) | 2025.01.28 |

✅ 1. Runtime.addShutdownHook()
Runtime.addShutdownHook()는 자바 애플리케이션이 종료될 때 실행할 코드를 등록하는 메서드이다. 이를 활용하면 프로그램이 종료되기 직전에 특정 작업(파일 저장, 리소스 정리 등)을 수행할 수 있다.
✅ 2. JVM 종료 이벤트란?
여기서 정상 또는 비정상 종료의 정의는 명세서에 나와 있다. 자바의 가상 머신은 두 가지 종류의 이벤트를 받아 종료한다.
정상 종료
- 프로그램이 정상적으로 종료될 때
- System.exit()가 호출될 때
비정상 종료
- Ctrl + C(사용자 인터럽트)
- 사용자 로그오프 또는 시스템 종료 등 시스템 이벤트
⚠️ 하지만 아래와 같은 경우에는 실행되지 않을 수 있다.
- kill -9 (강제 종료)
- OutOfMemoryError 발생
📌 정리하자면
- 프로그램이 정상 종료되거나, Ctrl + C 같은 신호로 종료될 때 실행됨
- System.exit()가 호출되거나, JVM이 정상 종료될 때도 실행됨
- 하지만 kill -9(강제 종료) 또는 OutOfMemoryError 같은 예외 상황에서는 실행되지 않을 수도 있음
✅ 3. 코드 흐름
public class ShutdownHookExample { public static void main(String[] args) { // 종료 훅 등록 Runtime.getRuntime().addShutdownHook(new Thread(() -> { System.out.println("프로그램이 종료되기 전에 실행할 작업"); })); System.out.println("프로그램 실행 중..."); try { Thread.sleep(5000); // 5초 동안 실행 유지 } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("프로그램 종료"); } }
💡 실행 결과 (콘솔▼)
프로그램 실행 중... 프로그램 종료 프로그램이 종료되기 전에 실행할 작업
JVM이 종료되기 직전에 미리 등록한 코드(Shutdown Hook)가 종료 후 실행되는 것을 콘솔에서 확인 가능하다.
✅ 4. 언제 써?
- 파일 저장 또는 로그 기록: 프로그램이 종료되기 전에 데이터를 저장할 때
- 리소스 정리 (예: 데이터베이스 연결 해제) :실행 중이던 프로세스를 정리 할 때 유용함
- 서버 애플리케이션에서 클린업 작업 수행: 웹 서버가 종료시 특정 정리 작업을 수행 가능
✅ 사용 예제
public class ShutdownHookTest { // HookThread는 Thread 클래스를 상속받아 run() 메서드를 오버라이드한 스레드이다. // 이 스레드는 JVM 이 종료될 때 실행하고, 실행시 "Hook Run"을 출력한다. static class HookThread extends Thread { @Override public void run() { System.out.println("Hook Run"); } } public static void main(String[] args) { // JVM 종료 시 실행될 Shutdown Hook 등록 // Runtime.getRuntime()을 통해 Runtime 객체 가져오기 // addShutdownHook()을 호출하여 HookThread를 등록한다 Runtime.getRuntime().addShutdownHook(new HookThread()); System.out.println("End"); } }
메인에서 "End"를 출력한 후 프로그램이 종료된다. JVM 종료시 Shutdown Hook이 실행된다.
📌 아래처럼 예외가 발생하면?
“End”는 출력되지 않지만 “Hook Run”이 출력된다.
// ... public static void main(String[] args) { Runtime.getRuntime().addShutdownHook(new HookThread()); int errorNum = 1 / 0; System.out.println("End"); } }
Exception in thread "main" java.lang.ArithmeticException: / by zero at ShutdownHookTest.main(ShutdownHookTest.java:10) Hook Run
📌 콘솔에서 sleep 동안 인터럽트(Ctrl+C)를 주는 경우
“End”는 출력되지 않지만 “hook Run”이 출력된다.
// ... public static void main(String[] args) { Runtime.getRuntime().addShutdownHook(new HookThread()); try { System.out.println("sleep 3s"); Thread.sleep(3000); } catch (Exception e) { e.printStackTrace(); } System.out.println("End"); } }
sleep 3s End Hook Run
메인에서 일어나는 일
- 먼저 "sleep 3s" 출력된다.
- Thread.sleep(3000); → 3초 동안 대기 (프로그램이 바로 종료되지 않도록)
- 만약 Thread.sleep() 중 인터럽트가 발생하면 예외 처리
- "End"를 출력한 후 프로그램이 종료됨
- JVM이 종료되면서 Shutdown Hook 실행됨 → Hook Run 출력
⭐ 순서를 지정할 수 없음❌
다중 스레드 실행처럼 여러 개의 Hook이 있을 경우 실행 순서는 정해져 있지 않다. JVM은 Hook 쓰레드를 등록된 순서대로 실행한다고 보장하지 않기 때문에, 두 쓰레드가 어떤 순서로 실행될지는 JVM에 따라 달라질 수 있다.
public class ShutdownHookTest { static class HookThread extends Thread { @Override public void run() { System.out.println("Hook Run1"); } } static class HookThread2 extends Thread { @Override public void run() { System.out.println("Hook Run2"); } } public static void main(String[] args) { Runtime.getRuntime().addShutdownHook(new HookThread()); Runtime.getRuntime().addShutdownHook(new HookThread2()); System.out.println("End"); } }
첫 번째 실행 결과
End Hook Run1 Hook Run2
두번째 실행 결과
End Hook Run2 Hook Run1
⭐ 등록된 Shutdown Hook 실행 차단 🙅🏻♀️
사용할 일이 별로 없을 것 같지만, Runtime.halt(int)를 사용하면 등록된 Shutdown Hook을 실행하지 않고 종료된다.
만약 종료 중에 Halt가 호출될 경우 (종료 중이라면 등록된 Shutdown Hook 쓰레드들이 동시에 실행되는 상태) 실행 중인 Hook이 마칠 떄까지 대기하지 않고, 종료한다.
아래 예제를 보면 종료되기 전에 halt() 메소드를 호출하였으므로 등록된 Hook이 실행되지 않는다.
public class ShutdownHookTest { static class HookThread extends Thread { @Override public void run() { System.out.println("Hook Run1"); } } static class HookThread2 extends Thread { @Override public void run() { System.out.println("Hook Run2"); } } public static void main(String[] args) { // Shutdown Hook 등록 Runtime.getRuntime().addShutdownHook(new HookThread()); Runtime.getRuntime().addShutdownHook(new HookThread2()); System.out.println("End"); // JVM을 강제로 종료 Runtime.getRuntime().halt(0); } }
🔥halt(0)의 역할
Runtime.getRuntime().halt(0)은 JVM을 강제로 종료시키는 메서드이다. halt() 메서드는 정상적인 종료 절차를 따르지 않기 때문에, Shutdown Hook이 실행되지 않는다.
- halt()는 JVM이 종료되는 즉시 모든 후속 작업을 중단하고 종료한다.
- 따라서, halt()를 호출하면 등록된 Shutdown Hook은 실행되지 않는다.
📌 halt(0) 호출 전후의 차이
정상적인 종료 (System.exit() 등)에서는 JVM이 종료되기 전에 Shutdown Hook이 실행된다.
End Hook Run1 Hook Run2
하지만 halt(0) 호출 시, halt(0)은 즉시 JVM을 종료시키기 때문에, Shutdown Hook은 실행되지 않는다.
End
⭐ Shutdown Hook이 실행되면, Hook을 추가, 삭제할 수 없음❌
Shutdown Hook의 동작에 대한 제약이 있는데, Shutdown Hook이 실행되기 시작하면 그 시점에 더 이상 새로운 Shutdown Hook을 추가하거나 기존의 Shutdown Hook을 삭제할 수 없다.
삭제 메서드 Runtime.removeShutdownHook()
만약 시도한다면? IllegalStateException 예외가 발생한다.
아래 예제는 예외가 발생하는 경우이다. Shutdown Hook에 추가한 Hook Thread에 새로운 Hook을 추가하였다. 따라서 종료되면서 IllegalStateException 예외가 발생한다.
public class ShutdownHookTest { static class HookThread extends Thread { @Override public void run() { Runtime.getRuntime().addShutdownHook(new HookThread()); System.out.println("Hook Run1"); } } // ... }
⚠️ Runtime.addShutdownHook() 사용 시 유의사항
✔️ 스레드는 어렵다
- Shutdown Hook 은 별도의 스레드에서 실행되므로, 원하는 대로 동작하지 않을 수 있음
- 스레드 동작을 예상하기 어렵고, 디버깅이 까다로울 수 있음
✔️ 동시에 실행되므로 thread-safe 하게 작성할 것!
- 프로그램이 종료될 때, 등록된 모든 Shutdown Hook 쓰레드가 동시에 실행됨
- 다른 쓰레드들도 실행 중일 가능성이 있으므로, 데드락(Deadlock) 발생 가능성을 고려해야 함
- 공유 자원(파일, DB 등)에 접근할 때는 동기화(synchronization)를 신경 써야 함
✔️ 무조건 실행된다는 보장이 없음
- kill -9
(강제 종료) 또는 OutOfMemoryError
발생 시 실행되지 않을 수도 있음
- 따라서 Shutdown Hook을 100% 신뢰하면 안 됨!
- 중요한 작업은 별도로 종료 메서드(cleanup method)를 구현하는 것이 안전함
✔️ Hook 쓰레드에서 너무 많은 시간을 소모하면 안 됨
- 시스템 종료 중에 Shutdown Hook
이 실행되는데, 너무 오래 걸리면 시스템이 무시하고 강제 종료할 수 있음
- 따라서, 최소한의 작업만 수행하는 것이 바람직하다
'프로그래밍언어 > Java' 카테고리의 다른 글
[Java] 자바 소켓 통신 Gson + BufferedWriter 사용중 host 에러 해결법 (11) | 2025.02.10 |
---|---|
[Eclipse] 내가 보려고 만든 이클립스 유용한 단축키 (12) | 2025.02.05 |
[Java] 자바 배열 정렬 할 때 오버플로우 방지하는 법 (11) | 2025.02.01 |
[Spring] 스프링 Spring MVC 흐름 완벽 정리: 초보자도 이해하는 MVC 패턴 (19) | 2025.01.28 |
[JSP & Servlet] URL 매핑 (9) | 2025.01.28 |