JAVA Runtime.addShutdownHook()方法

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

时间: 2024-10-12 15:20:09

JAVA Runtime.addShutdownHook()方法的相关文章

Java Runtime.availableProcessors()方法

Java Runtime.availableProcessors()方法用法实例教程. 描述 java.lang.Runtime.availableProcessors() 方法返回到Java虚拟机的可用的处理器数量.此值可能会改变在一个特定的虚拟机调用.应用程序可用处理器的数量是敏感的,因此偶尔查询该属性,并适当地调整自己的资源使用情况. 声明 以下是声明java.lang.Runtime.availableProcessors()方法 public int availableProcesso

Java Runtime.exec()的使用

Sun的doc里其实说明还有其他的用法: exec(String[] cmdarray, String[] envp, File dir) Executes the specified command and arguments in a separate process with the specified environment and working directory. 那个dir就是调用的程序的工作目录,这句其实还是很有用的. Windows下调用程序 Process proc =Ru

Runtime.addShutdownHook理解

一.Runtime.addShutdownHook理解 在看别人的代码时,发现其中有这个方法,便顺便梳理一下. void java.lang.Runtime.addShutdownHook(Thread hook) 该方法用来在jvm中增加一个关闭的钩子.当程序正常退出,系统调用 System.exit方法或虚拟机被关闭时才会执行添加的shutdownHook线程.其中shutdownHook是一个已初始化但并不有启动的线 程,当jvm关闭的时候,会执行系统中已经设置的所有通过方法addShut

Runtime.addShutdownHook()(译)

序言: 每一个Java程序都可以为JVM增加一个关闭钩子.JVM将在关闭之前执行关闭钩子中的指令. 问题: 一个程序可能需要在退出前执行一些指令.程序可能由于下列原因而退出: 所有的线程已经执行完毕 调用System.exit() 用户输入Ctrl+C 系统级关闭或用户注销 适用场景: 保存应用状态,例如,当多数IDE退出时,它们将记忆最后的视图有哪些. 关闭某些数据库连接. 将应用关闭的消息发送给系统管理员. 解决方案: 关闭钩子支持所有这些场景.应用可以增加一个关闭钩子,JVM将在应用退出时

Java RunTime Environment (JRE) or Java Development Kit (JDK) must be available in order to run Eclip

本文解决的是在普通用户下执行eclipse可行但是切换到root之后就出现的问题 Java RunTime Environment (JRE) or Java Development Kit (JDK) must be available in order to run Eclipse. No java virtual machine was found after searching the following locations:- 解决办法是在终端进入你的eclipse目录,然后输入: m

A Java Runtime Environment (JRE) or Java Development Kit (JDK) must be avail

A Java Runtime Environment (JRE) or Java Development Kit (JDK) must be avail Java RunTime Environment (JRE) or Java Development Kit (JDK) must be available in order to run Eclipse. No java virtual machine was found after searching the following locat

ubuntu myeclipse 启动时提示 A Java Runtime Environment (JRE) or Java Development Kit (JDK) must be avail ....

jdk已经安装过但是启动eclipse时提示“A Java Runtime Environment (JRE) or Java Development Kit (JDK) must be avail ” 解决方法 终端进入你的eclipse目录,然后输入: mkdir jrecd jre ln -s 你的JDK目录/bin bin

使用Maven运行Java ain的方法(转)

使用Maven运行Java Main的方法(既Java Application项目),可以有如下方式解决: 1.将Maven项目导入到eclipse中,然后直接项目右键[Run As]->[Java Application]. 2.直接指定jar包的Main入口(参考:http://www.cnblogs.com/EasonJim/p/6481704.html),通过Maven命令打包出jar文件,然后运行java -jar Application.jar. 3.通过Maven插件exec-ma

Java Runtime 执行系统命令行程序

以前写过一篇文章,介绍通过 Java 的 Runtime 类执行操作系统命令行程序:Java调用linux系统shell执行命令.最近项目中又有需要用这个方法,在使用过程中遇到了一些新的问题,感觉以前没有弄清楚,故在此做补充学习记录. 先说明一下这次的需求,在 Java 程序中控制 Hadoop 命令执行 MapReduce 作业,并获取其输出内容.本来没有什么特殊,但由于 MR 执行的是 Kmeans 算法,会产递归产生多个 MR 程序,在捕获输出的时候就只有简单的几句提示,没有 MR 作业的