JAVA Runtime.addShutdownHook()方法{拿到线程句柄,在程序关闭之前调用释放资源}

29 篇文章 0 订阅

Runtime#addShutDownHook方法是给虚拟机增加一个虚拟机关闭时的调用钩子,在虚拟机关闭的时候调用这些钩子线程。还是非常有用的一个方法,最直接的用法就是监控了,因为其是在虚拟机临关闭时被调用,所以天生可以记录虚拟机关闭这件事情,及其相关的信息;再就是清理资源什么的,也可以做一个钩子线程,这样就不用再应用中为这些清理资源的操作找合适的位置了;

下面先翻译一下这个方法的Java doc,在网上找到几篇翻译,都出自一个版本,错误挺多的,这里重新翻译一下:

doc的第一句话是Registers a new virtual-machine shutdown hook.网上的翻译的版本将其翻译成了注册一个新的虚拟机来关闭钩子,这样翻译从语法的角度来讲就是不对的嘛,一句话里Register和Shutdown都成了动词。很简单的一句话,就是注册一个新的虚拟机关闭钩子。可以用下面的代码验证一下,主程序和这些钩子线程是不是运行在一个JVM中:

  1. public static void main(String[] args) {  
  2.           
  3.         Runtime.getRuntime().addShutdownHook(new Thread(){  
  4.             @Override  
  5.             public void run() {  
  6.                     System.out.println("I am still alive!");  
  7.                     try {  
  8.                         Thread.currentThread().sleep(1000);  
  9.                         System.out.println(Runtime.getRuntime().toString());  
  10.                         System.out.println(Runtime.getRuntime().hashCode());  
  11.                     } catch (InterruptedException e) {  
  12.                         e.printStackTrace();  
  13.                     }  
  14.             }  
  15.         });  
  16.           
  17.         try {  
  18.             Thread.currentThread().sleep(1000);  
  19.         } catch (InterruptedException e) {  
  20.             // TODO Auto-generated catch block  
  21.             e.printStackTrace();  
  22.         }  
  23.         System.out.println(Runtime.getRuntime().toString());  
  24.         System.out.println(Runtime.getRuntime().hashCode());  
  25.         System.out.println("I am exit!");  
  26.     }  
public static void main(String[] args) {
                
                Runtime.getRuntime().addShutdownHook(new Thread(){
                        @Override
                        public void run() {
                                        System.out.println("I am still alive!");
                                        try {
                                                Thread.currentThread().sleep(1000);
                                                System.out.println(Runtime.getRuntime().toString());
                                                System.out.println(Runtime.getRuntime().hashCode());
                                        } catch (InterruptedException e) {
                                                e.printStackTrace();
                                        }
                        }
                });
                
                try {
                        Thread.currentThread().sleep(1000);
                } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                }
                System.out.println(Runtime.getRuntime().toString());
                System.out.println(Runtime.getRuntime().hashCode());
                System.out.println("I am exit!");
        }
主程序中打印出的Runtime的对象的信息和钩子线程中打印出的Runtime的信息是一致的。

下面开始正式的翻译:

Runtime#addShutDownHook方法会注册一个新的 虚拟机关闭钩子;

Java虚拟机只在响应下面两种事件时关闭:

1.当最后的非守护进程结束时,程序正常结束;或者当exit方法(统称,比如System.exit()方法)被调用时

2.JVM响应用户的中断操作,例如键入了^C或者一个系统级的事件,例如用户退出登录或者系统(JVM所在的系统,比如PC的操作系统,Android)关闭。

一个关闭钩子是一个简单初始化还没有启动的线程。当虚拟机开始进入关闭阶段时,虚拟机将以不确定的顺序启动所有已经注册的关闭钩子,当所有的钩子线程结束时,如果finalization-on-exit 启用,JVM将接着运行所有还没被调用的finalizer。最后,虚拟机停止。注意,在JVM的关闭阶段,守护线程将持续运行,如果JVM的关闭阶段是通过调用exit方法进入的,非守护的线程也会在JVM的关闭阶段持续运行。

一旦进入关闭工序,JVM将只能通过调用halt方法停止,这个方法将强制结束虚拟机。

一旦关闭工序开始,虚拟机不能再被注册新的ShutDown hook,也不能撤销之前注册的钩子。这两个操作都会导致抛出一个IllegalStateException错误。

ShutDown钩子运行在Java虚拟机整个生命周期的一个很微妙的时刻,虚拟机生命周期的最后阶段,因此在编写程序时应该十分小心。这些钩子线程应该都是线程安全的,并且要避免任何可能的死锁的发生。钩子线程不应该依赖于绑定的服务,这些绑定的服务包括,注册到虚拟机的其他的钩子线程和在JVM已经开启关闭工序时钩子线程自己。使用其他基于线程的服务,像AWT的事件分发线程,可能导致死锁。

关闭钩子线程中未捕获的错误的处理方式跟其他的线程一样,通过调用ThreadGroup#uncaughtException方法,这个方法的默认实现是打印错误堆栈信息(System#err),然后结束线程;这个方法不会导致虚拟机结束或终止。

在罕见的情况下,虚拟机可能会abort,也就是说,没有干净的关闭而直接停止运行。这种情况会发生在当虚拟机被外部的力量结束时。例如,Unix中的SIGKILL信号或者window平台中的TerminateProcess被调用。虚拟机也可能在一个native的方法出错时abort,例如,毁坏的内部数据结构或者尝试访问不存在的内存。如果虚拟机abort,将不能保证关闭钩子线程被完整运行。


上边这一段是Runtime#addShutDownHook方法的注释。简单总结一下,钩子线程的启动时机:

1.虚拟机自己结束时会调用,比如程序运行完成,或者用户跟虚拟机交互之后,虚拟机接收到退出信号,自己结束

2.外部力量结束虚拟机时,不能保证钩子线程启动,比如在windows平台中,启动任务管理器,直接将这个Java虚拟机关闭进程,这种情况下不能保证钩子线程一定会被调用


上边的1和2都可以通过稍微修改下最上边的程序验证。
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值