前言
当你认真的去看一个组件的源码的时候,你会经常看见这种关闭钩子的函数,如果你不了解的话,谷歌一下,你就会发现如下文章就是搜索引擎出来的第一篇,不愧是出自我们优秀的厮哒哒之笔。
正文
Java 程序经常也会遇到进程挂掉的情况,一些状态没有正确的保存下来,这时候就需要在 JVM 关掉的时候执行一些清理现场的代码。JAVA 中的 ShutdownHook 提供了比较好的方案。
JDK提供了Java.Runtime.addShutdownHook(Thread hook)方法,可以注册一个JVM关闭的钩子,这个钩子可以在一下几种场景中被调用:
1、程序正常退出
2、使用 System.exit()
3、终端使用 Ctrl+C 触发的中断
4、系统关闭
5、OutOfMemory 宕机
6、使用 Kill pid 命令干掉进程(注:在使用 kill -9 pid 时,是不会被调用的)
下面
是JDK1.7中关于钩子的定义:
public void addShutdownHook(Thread hook)
参数:
hook – An initialized but unstarted Thread object
抛出:
IllegalArgumentException – If the specified hook has already been registered, or if it can be determined that the hook is already running or has already been run
IllegalStateException – If the virtual machine is already in the process of shutting down
SecurityException – If a security manager is present and it denies RuntimePermission(\”shutdownHooks\”)
从以下版本开始:
1.3
另请参见:
removeShutdownHook(java.lang.Thread), halt(int), exit(int)
首先来测试第一种
程序正常退出的情况
1package com.hook;
2
3import java.util.concurrent.TimeUnit;
4
5public class HookTest
6{
7 public void start()
8 {
9 Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
10 @Override
11 public void run()
12 {
13 System.out.println(\"Execute Hook.....\");
14 }
15 }));
16 }
17
18 public static void main(String[] args)
19 {
20 new HookTest().start();
21 System.out.println(\"The Application is doing something\");
22
23 try
24 {
25 TimeUnit.MILLISECONDS.sleep(5000);
26 }
27 catch (InterruptedException e)
28 {
29 e.printStackTrace();
30 }
31 }
32}
运行结果:
1The Application is doing something
2Execute Hook.....
如上可以看到,当main线程运行结束之后就会调用关闭钩子。
下面再来测试第五种情况(顺序有点乱,表在意这些细节)
OutOfMemory 宕机
1package com.hook;
2
3import java.util.concurrent.TimeUnit;
4
5public class HookTest2
6{
7 public void start()
8 {
9 Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
10 @Override
11 public void run()
12 {
13 System.out.println(\"Execute Hook.....\");
14 }
15 }));
16 }
17
18 public static void main(String[] args)
19 {
20 new HookTest().start();
21 System.out.println(\"The Application is doing something\");
22 byte[] b = new byte[500*1024*1024];
23 try
24 {
25 TimeUnit.MILLISECONDS.sleep(5000);
26 }
27 catch (InterruptedException e)
28 {
29 e.printStackTrace();
30 }
31 }
32
33}
运行参数设置为:-Xmx20M 这样可以保证会有 OutOfMemoryError 的发生。
运行结果:
1The Application is doing something
2Exception in thread \"main\" java.lang.OutOfMemoryError: Java heap space
3 at com.hook.HookTest2.main(HookTest2.java:22)
4Execute Hook.....
可以看到程序遇到内存溢出错误后调用关闭钩子,与第一种情况中,程序等待 5000ms 运行结束之后推出调用关闭钩子不同。
接下来再来测试第三种情况
终端使用 Ctrl+C 触发的中断
1package com.hook;
2
3import java.util.concurrent.TimeUnit;
4
5public class HookTest3
6{
7 public void start()
8 {
9 Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
10 @Override
11 public void run()
12 {
13 System.out.println(\"Execute Hook.....\");
14 }
15 }));
16 }
17
18 public static void main(String[] args)
19 {
20 new HookTest3().start();
21 Thread thread = new Thread(new Runnable(){
22
23 @Override
24 public void run()
25 {
26 while(true)
27 {
28 System.out.println(\"thread is running....\");
29 try
30 {
31 TimeUnit.MILLISECONDS.sleep(100);
32 }
33 catch (InterruptedException e)
34 {
35 e.printStackTrace();
36 }
37 }
38 }
39
40 });
41 thread.start();
42 }
43
44}
在命令行中编译:javac com/hook/HookTest3.java
在命令行中运行:java com.hook.HookTest3 (之后按下Ctrl+C)
运行结果:
可以看到效果如预期。 还有几种情况就不一一列出了,有兴趣的读者可以把剩余的几个也测试一下。