码迷,mamicode.com
首页 > 编程语言 > 详细

JAVA Runtime.addShutdownHook()方法

时间:2014-11-08 12:05:12      阅读:193      评论:0      收藏:0      [点我收藏+]

标签:java   thread   线程安全   jvm   线程   

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

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

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

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都可以通过稍微修改下最上边的程序验证。



JAVA Runtime.addShutdownHook()方法

标签:java   thread   线程安全   jvm   线程   

原文地址:http://blog.csdn.net/xichenguan/article/details/40895719

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!