关于Shutdown钩子的查询

时间:2014-01-11 19:38:02

标签: java eclipse shutdown-hook

  1. 如果我已经正确使用它,每个java进程都与一个单独的JVM实例相关联,并且每个JVM实例都由OS提供了一个堆内存,这也是由操作系统在JVM终端上重新收集的。 So on termination even if there were some memory leaks all the memory will be reclaimed by the OS(Please correct if I have mistaken)
  2. 如果第1点为真,为什么我们必须使用关闭钩子。谷歌搜索后的一切主要建议释放所有资源和优雅的关机。 Even if it does not gracefully shutdown all the memory and resources would be freed?
  3. 我写了一个简单的关机钩子。在我的主线程中,我运行一个无限循环,然后使用Eclipse中的终止按钮终止进程。但是关闭钩子线程没有运行。 eclipse中的终止进程是否调用Runtime.getRuntime().halt(status),因为AFAIK突然终止了JVM而没有执行shutdown hook?
  4. 最后,如果我的主要代码如下所示 -

    public static void main(String args[]){
    Runtime.getRuntime().addShutdownHook(new Thread(new ShutDownHook()));
    System.out.println("Shutdown hook registered");
    System.out.println("Before calling exit");
    System.exit(0);
    System.out.println("After exit");       
    }
    

    为什么不打印After exit?当执行shutdown hook时,主线程必须继续执行并打印After exit

1 个答案:

答案 0 :(得分:3)

1)你是对的。

2)将回收Java进程的内存,但您可能希望进行其他清理,例如删除一些临时文件。

3)让我们转到Runtime#addShutdownHook(Thread)

的javadoc
  

Java虚拟机关闭以响应两种   事件:

     
      
  • 当最后一个非守护程序线程退出或时,程序正常退出   何时调用exit(等效,System.exit)方法,或

  •   
  • 虚拟机终止以响应用户中断,   例如键入^ C或系统范围的事件,例如用户注销或   系统关闭。

  •   

您必须查看Eclipse的源代码,但似乎Eclipse会终止该进程而不是发送System.exit(..)或发送用户中断。这可能会超过JVM,因此不会执行关闭挂钩。

4)您使用Runtime#addShutdownHook(Thread)添加的关闭挂钩已添加到static中的IdentityHashMap ApplicationShutdownHooks。该类在Shutdown初始化程序块中使用static类注册自己的关闭挂钩

static {
    try {
        Shutdown.add(1 /* shutdown hook invocation order */,
            false /* not registered if shutdown in progress */,
            new Runnable() {
                public void run() {
                    runHooks();
                }
            }
        );
        hooks = new IdentityHashMap<>();
    } catch (IllegalStateException e) {
        // application shutdown hooks cannot be added if
        // shutdown is in progress.
        hooks = null;
    }
}

runHooks()方法

static void runHooks() {
    Collection<Thread> 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) { }
    }
}

所以当前线程加入了所有其他线程。

何时

System.exit(0);

被调用,调用行Shutdown.sequence()的某个地方调用Shutdown.hooks()实现为

private static void runHooks() {
    for (int i=0; i < MAX_SYSTEM_HOOKS; i++) {
        try {
            Runnable hook;
            synchronized (lock) {
                // acquire the lock to make sure the hook registered during
                // shutdown is visible here.
                currentRunningHook = i;
                hook = hooks[i];
            }
            if (hook != null) hook.run();
        } catch(Throwable t) {
            if (t instanceof ThreadDeath) {
                ThreadDeath td = (ThreadDeath)t;
                throw td;
            }
        }
    }
}

Runnable中的hooks个对象之一就是我上面描述的内容。它不会产生新的Thread,而是与run()同时产生。

完成Shutdown.sequence()后,系统确实退出,因此最终的System.out.println()不会执行。