java面试题网站:www.javaoffers.com
Java中的JVM关闭钩子
(翻译篇)关机钩子 也叫 关闭钩子
关机钩子是一种特殊的构造,允许开发人员插入一段代码,以便在JVM关闭时执行。当我们需要在VM关闭时执行特殊的清理操作时,这就很方便了。
通常使用关机钩子处理的一般结构,如确保我们调用特殊过程在应用程序退出(调用system . exit(0))将不工作情况下VM关闭是由于外部原因(例如杀死请求从O / S),或由于资源问题(内存)。我们很快就会看到,shutdown钩子很容易解决这个问题,因为它允许我们提供一个任意的代码块,JVM在关闭时将调用这个代码块。
从表面上看,使用关机钩子是非常直接的。我们所要做的只是编写一个扩展java.lang的类。线程类,并在公共void run()方法中提供我们希望在关闭VM时执行的逻辑。然后,通过调用Runtime.getRuntime(). addshutdownhook (Thread)方法,将这个类的一个实例注册为VM的关机钩子。如果需要删除以前注册的关机钩子,运行时类也提供了removeShutdownHook(Thread)方法。
举例:
public class ShutDownHook
{
public static void main(String[] args)
{
Runtime.getRuntime().addShutdownHook(new Thread()
{
public void run()
{
System.out.println("Shutdown Hook is running !");
}
});
System.out.println("Application Terminating ...");
}
}
当我们运行上面的代码时,您将看到JVM在完成main方法的执行时调用了shutdown钩子。
输出:
Application Terminating ...
Shutdown Hook is running !
案例2
class ThreadChild extends Thread {
public void run() {
System.out.println("In clean up code");
System.out.println("In shutdown hook");
}
}
class Demo {
public static void main(String[] args) {
Runtime current = Runtime.getRuntime();
current.addShutdownHook(new ThreadChild());
for(int i = 1; i <= 10; i++)
System.out.println("2 X " + i + " = " + 2 * i);
}
}
输出
2 X 1 = 2
2 X 2 = 4
2 X 3 = 6
2 X 4 = 8
2 X 5 = 10
2 X 6 = 12
2 X 7 = 14
2 X 8 = 16
2 X 9 = 18
2 X 10 = 20
In clean up code
In shutdown hook
就是这么简单
虽然编写关机钩子非常简单,但要正确地使用关机钩子,就需要了解关机钩子背后的内部原理。因此,在本文中,我们将探索关机钩子设计背后的一些陷阱。
-
关机钩子在某些情况下可能不会被执行
首先要记住的是,不能保证shutdown钩子总是运行。如果JVM由于一些内部错误而崩溃,那么它可能在没有机会执行单个指令的情况下崩溃。同样,如果O/S给出一个SIGKILL (http://en.wikipedia.org/wiki/SIGKILL)信号(在Unix/Linux中kill -9)或TerminateProcess (Windows),那么应用程序就需要立即终止,甚至不需要等待任何清理活动。除了上述方法之外,还可以通过调用Runtime.halt()方法终止JVM,而不允许关机钩子运行。
当应用程序正常终止时(当所有线程结束时,或者当System.exit(0)被调用时),会调用Shutdown钩子。另外,当JVM由于外部原因关闭时,比如用户请求终止(Ctrl+C)、O/S发出的SIGTERM(正常的kill命令,不带-9),或者当操作系统关闭时。 -
一旦启动,关机钩子可以在完成前强制停止。
这实际上是前面解释的情况的一个特例。虽然钩子开始执行,但在操作系统关闭等情况下,它可能在完成之前被终止。在这种情况下,一旦给出了SIGTERM, O/S将等待进程在指定的时间内终止。如果进程没有在这个时间限制内终止,那么O/S通过发出一个SIGTERM(或Windows中的对应项)强制终止进程。因此,当关机钩子执行到一半的时候,很可能会发生这种情况。
因此,建议确保小心地编写关闭钩子,确保它们快速完成,并且不会导致死锁等情况。另外,JavaDoc[1]特别提到不应该在关机钩子中执行长计算或等待用户I/O操作。 -
我们可以有多个关机钩子,但是它们的执行顺序不能保证。
正如您可能已经正确猜到的addShutdownHook方法的名称(而不是setShutdownHook),您可以注册多个关机钩子。但是JVM并不保证这些多个钩子的执行顺序。JVM可以以任意顺序执行关机挂钩。而且,JVM可能并发地执行所有这些挂钩。. -
我们无法在关机钩子中注册/取消注册关机钩子
一旦JVM启动了关闭序列,就不允许添加或删除任何现有的关闭钩子。如果尝试这样做,JVM将抛出IllegalStateException。 -
一旦启动了关闭序列,就只能通过Runtime.halt()来停止它。
一旦启动了关闭序列,只有Runtime.halt()(强制终止JVM)可以停止关闭序列的执行(除了SIGKILL等外部影响)。这意味着在关机钩子中调用System.exit()将不起作用。实际上,如果在关机钩子中调用System.exit(), VM可能会被卡住,我们可能不得不强制终止进程。 -
使用关机钩子需要安全权限。
如果我们使用Java安全管理器,那么执行添加/删除关闭钩子的代码需要在运行时拥有关闭钩子权限。如果我们在安全环境中未经允许调用此方法,则会导致SecurityException。
引用:
http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/Runtime.html addShutdownHook (java.lang.Thread)