JAVA 핵심 지식 포인트-Shutdown Hook 을 이용 하여 시스템 자원 방출

목차
Shutdown Hook 실행 원리
ShutdownHook 적용 필드
참고서:《자바 특전 사(상권)》 
System.exit(int status)가 발생 했 을 때 시스템 이 종료 되 기 전에 약간의 임 무 를 수행 하여 자원 방면 의 회수 작업 을 하고 싶 습 니 다.Shutdown Hook 은 이 목적 을 달성 할 수 있 습 니 다.이것 은 hook 의 사고방식 을 이용 하여 실현 하고 어떤 때 는 이 를'갈고리'라 고도 부 릅 니 다.
시스템 에서 Runtime.getRuntime().exec(String command)나 new ProcessBuilder(List command)를 통 해 하위 프로 세 스(Process)를 시작 하면 이 하위 프로 세 스 가 계속 실행 중 입 니 다.현재 프로 세 스 가 종료 되 었 을 때 하위 프로 세 스 가 종료 되 는 것 은 아 닙 니 다.그러나 이 때 업무 상 종료 하 기 를 원 하면 이용 할 수 있 습 니 다. ShutdownHook 。예 를 들 어 다음 테스트 사례: 
public class ShutdownHookTest {

	public static void main(String[] args) {
		Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
			public void run() {
				System.out.println("  ShutdownHook    ,      ...");
			}
		}));
		Runtime.getRuntime().removeShutdownHook(new Thread());
		System.exit(1);
		System.out.println("     ...");
	}
}

실행 결과:
     ...
  ShutdownHook    ,      ...

메모:입력 매개 변 수 는 new Thread()를 통 해 만 든 스 레 드 대상 입 니 다.자바 프로 세 스 가 exit()를 호출 할 때 이 스 레 드 대상 의 start()방법 으로 실행 되 므 로 손 으로 먼저 시작 하지 마 십시오.또한,이러한 리 셋 스 레 드 는 고정 순환 프로그램 으로 설정 하지 마 십시오.그렇지 않 으 면 종료 할 수 없습니다.
Shutdown Hook 실행 원리
java.lang 패키지 아래 에 Shutdown 클래스 가 있 습 니 다.Runnable[]hooks 배열 을 제공 합 니 다.배열 의 길 이 는 10 입 니 다.즉,최대 10 개의 hook(프로그램 이 몇 개의 스 레 드 를 기록 하 는 지 와 무관 합 니 다)를 정의 하고 add()방법 으로 새로운 hook 대상 을 등록 합 니 다. 
    // The system shutdown hooks are registered with a predefined slot.
    // The list of shutdown hooks is as follows:
    // (0) Console restore hook
    // (1) Application hooks
    // (2) DeleteOnExit hook
    private static final int MAX_SYSTEM_HOOKS = 10;
    private static final Runnable[] hooks = new Runnable[MAX_SYSTEM_HOOKS];
    /* Add a new shutdown hook.  Checks the shutdown state and the hook itself,
     * but does not do any security checks.
     */
    static void add(int slot, Runnable hook) {
        synchronized (lock) {
            if (state > RUNNING)
                throw new IllegalStateException("Shutdown in progress");

            if (hooks[slot] != null)
                throw new InternalError("Shutdown hook at slot " + slot + " already registered");

            hooks[slot] = hook;
        }
    }
    

java.lang.ApplicationShutdown Hooks 의 static 익명 블록 에 add()방법 으로 hook 를 등록 하 였 습 니 다.run()방법 내부 에서 내 부 를 실행 하 는 정적 방법 runHooks()는 내부 에 Identity HashMap 으로 hook 정 보 를 저장 하고 add()방법 으로 추가 할 수 있 으 며 프로그램 에서 정의 하 는 리 셋 스 레 드 를 여기에 두 었 습 니 다.그 자체 가 hook 형식 으로 hooks 목록 에 존재 합 니 다. 
package java.lang;

import java.util.*;

/*
 * Class to track and run user level shutdown hooks registered through
 * {@link Runtime#addShutdownHook Runtime.addShutdownHook}.
 *
 * @see java.lang.Runtime#addShutdownHook
 * @see java.lang.Runtime#removeShutdownHook
 */

class ApplicationShutdownHooks {
    static {
        Shutdown.add(1 /* shutdown hook invocation order */,
            new Runnable() {
                public void run() {
                    runHooks();
                }
            });
    }

    /* The set of registered hooks */
    private static IdentityHashMap hooks = new IdentityHashMap();

    private void ApplicationShutdownHooks() {}

    /* Add a new shutdown hook.  Checks the shutdown state and the hook itself,
     * but does not do any security checks.
     */
    static synchronized void add(Thread hook) {
	if(hooks == null)
	    throw new IllegalStateException("Shutdown in progress");

	if (hook.isAlive())
	    throw new IllegalArgumentException("Hook already running");

	if (hooks.containsKey(hook))
	    throw new IllegalArgumentException("Hook previously registered");

        hooks.put(hook, hook);
    }

    /* Remove a previously-registered hook.  Like the add method, this method
     * does not do any security checks.
     */
    static synchronized boolean remove(Thread hook) {
	if(hooks == null)
	    throw new IllegalStateException("Shutdown in progress");

	if (hook == null) 
	    throw new NullPointerException();

	return hooks.remove(hook) != null;
    }

    /* Iterates over all application hooks creating a new thread for each
     * to run in. Hooks are run concurrently and this method waits for 
     * them to finish.
     */
    static void runHooks() {
	Collection threads;
	synchronized(ApplicationShutdownHooks.class) {
	    threads = hooks.keySet();
	    hooks = null;
	}

	for (Thread hook : threads) {
	    hook.start();
	}
	for (Thread hook : threads) {
	    try {
		hook.join();
	    } catch (InterruptedException x) { }
	}
    }
}

Runtime.getRuntime().addShutdownHook(Thread hook)방법 을 호출 할 때 ApplicationShutdownHooks.add(Thread hook)를 간접 적 으로 호출 하여 Identity HashMap 에 스 레 드 를 넣 고 Runtime.getRuntime().removeShutdownHook(Thread)을 사용 하여 갈고리 스 레 드 를 삭제 합 니 다. 
public void addShutdownHook(Thread hook) {
	SecurityManager sm = System.getSecurityManager();
	if (sm != null) {
	    sm.checkPermission(new RuntimePermission("shutdownHooks"));
	}
	ApplicationShutdownHooks.add(hook);
    }
public boolean removeShutdownHook(Thread hook) {
	SecurityManager sm = System.getSecurityManager();
	if (sm != null) {
	    sm.checkPermission(new RuntimePermission("shutdownHooks"));
	}
	return ApplicationShutdownHooks.remove(hook);
    }

System.exit(int status)방법 을 호출 할 때 Shutdown.exit(int status)방법 을 간접 적 으로 호출 하고 sequence()-->runHooks()방법 을 호출 합 니 다. 
    /* Invoked by Runtime.exit, which does all the security checks.
     * Also invoked by handlers for system-provided termination events,
     * which should pass a nonzero status code.
     */
    static void exit(int status) {
	boolean runMoreFinalizers = false;
	synchronized (lock) {
	    if (status != 0) runFinalizersOnExit = false;
	    switch (state) {
	    case RUNNING:	/* Initiate shutdown */
		state = HOOKS;
		break;
	    case HOOKS:		/* Stall and halt */
		break;
	    case FINALIZERS:
		if (status != 0) {
		    /* Halt immediately on nonzero status */
		    halt(status);
		} else {
		    /* Compatibility with old behavior:
		     * Run more finalizers and then halt
		     */
		    runMoreFinalizers = runFinalizersOnExit;
		}
		break;
	    }
	}
	if (runMoreFinalizers) {
	    runAllFinalizers();
	    halt(status);
	}
	synchronized (Shutdown.class) {
	    /* Synchronize on the class object, causing any other thread
             * that attempts to initiate shutdown to stall indefinitely
	     */
	    sequence();
	    halt(status);
	}
    }
    /* The actual shutdown sequence is defined here.
     *
     * If it weren't for runFinalizersOnExit, this would be simple -- we'd just
     * run the hooks and then halt.  Instead we need to keep track of whether
     * we're running hooks or finalizers.  In the latter case a finalizer could
     * invoke exit(1) to cause immediate termination, while in the former case
     * any further invocations of exit(n), for any n, simply stall.  Note that
     * if on-exit finalizers are enabled they're run iff the shutdown is
     * initiated by an exit(0); they're never run on exit(n) for n != 0 or in
     * response to SIGINT, SIGTERM, etc.
     */
    private static void sequence() {
	synchronized (lock) {
	    /* Guard against the possibility of a daemon thread invoking exit
	     * after DestroyJavaVM initiates the shutdown sequence
	     */
	    if (state != HOOKS) return;
	}
	runHooks();
	boolean rfoe;
	synchronized (lock) {
	    state = FINALIZERS;
	    rfoe = runFinalizersOnExit;
	}
	if (rfoe) runAllFinalizers();
    }
    /* Run all registered shutdown hooks
     */
    private static void runHooks() {
	/* We needn't bother acquiring the lock just to read the hooks field,
	 * since the hooks can't be modified once shutdown is in progress
	 */
	for (Runnable hook : hooks) {
	    try {
		if (hook != null) hook.run();
	    } catch(Throwable t) { 
		if (t instanceof ThreadDeath) {
   		    ThreadDeath td = (ThreadDeath)t;
		    throw td;
		} 
	    }
	}
    }

순환 중인 hook 대상 은 응용 프로그램 Shutdown Hooks 의 익명 블록 에 의 해 정의 되 기 때문에 응용 프로그램 Shutdown Hooks 류 의 run()방법 을 호출 하고 runHooks()방법 을 호출 합 니 다.이 runHooks()방법 은 다음 과 같 습 니 다. 
/* Iterates over all application hooks creating a new thread for each
     * to run in. Hooks are run concurrently and this method waits for 
     * them to finish.
     */
    static void runHooks() {
	Collection threads;
	synchronized(ApplicationShutdownHooks.class) {
	    threads = hooks.keySet();
	    hooks = null;
	}

	for (Thread hook : threads) {
	    hook.start();
	}
	for (Thread hook : threads) {
	    try {
		hook.join();
	    } catch (InterruptedException x) { }
	}
    }

이 방법 에서 모든 Thread 를 꺼 내 서 스 레 드 를 시작 합 니 다.마지막 으로 join()방법 으로 각 스 레 드 가 끝 날 때 까지 기다 리 는 동작 입 니 다.다시 말 하면 프로 세 스 가 닫 히 기 전에 여러 개의 리 셋 작업 에 대한 처리 방식 은 모든 작업 이 하나의 스 레 드 에서 직렬 로 처리 되 는 것 이 아 닙 니 다.  
ShutdownHook 적용 필드
  • 프로그램 이 정상적으로 종료
  • System.exit()사용
  • 터미널 에서 Ctrl+C 를 사용 하여 터치 하 는 인 터 럽 트
  • 시스템 종료
  • OutOf Memory 다운
  • Kill pid 명령 을 사용 하여 프로 세 스 를 제거 합 니 다(비고:kill-9 pid 를 사용 할 때 호출 되 지 않 습 니 다)
  • 좋은 웹페이지 즐겨찾기