JDK Hook
提供了Java.Runtime.addShutdownHook(Thread hook)方法,可以注册一个JVM关闭的钩子,这个钩子可以在一下几种场景中被调用:
Registers a new virtual-machine shutdown hook.
The Java virtual machine shuts down in response to two kinds of events:
- 程序正常退出 或调用 system.exit()方法
The program exits normally, when the last non-daemon thread exits or when the exit (equivalently, System.exit) method is invoked, or
- 终端使用Ctrl+C触发的中断或者系统登出(log off) 或者系统shotdown
The virtual machine is terminated in response to a user interrupt, such as typing ^C (Ctrl+C), or a system-wide event, such as user logoff or system shutdown.
A shutdown hook is simply an initialized but unstarted thread. When the virtual machine begins its shutdown sequence it will start all registered shutdown hooks in some unspecified order and let them run concurrently. When all the hooks have finished it will then run all uninvoked finalizers if finalization-on-exit has been enabled. Finally, the virtual machine will halt. Note that daemon threads will continue to run during the shutdown sequence, as will non-daemon threads if shutdown was initiated by invoking the exit method.
Once the shutdown sequence has begun it can be stopped only by invoking the halt method, which forcibly terminates the virtual machine.
Once the shutdown sequence has begun it is impossible to register a new shutdown hook or de-register a previously-registered hook. Attempting either of these operations will cause an IllegalStateException to be thrown.
Shutdown hooks run at a delicate time in the life cycle of a virtual machine and should therefore be coded defensively. They should, in particular, be written to be thread-safe and to avoid deadlocks insofar as possible. They should also not rely blindly upon services that may have registered their own shutdown hooks and therefore may themselves in the process of shutting down. Attempts to use other thread-based services such as the AWT event-dispatch thread, for example, may lead to deadlocks.
Shutdown hooks should also finish their work quickly. When a program invokes exit the expectation is that the virtual machine will promptly shut down and exit. When the virtual machine is terminated due to user logoff or system shutdown the underlying operating system may only allow a fixed amount of time in which to shut down and exit. It is therefore inadvisable to attempt any user interaction or to perform a long-running computation in a shutdown hook.
Uncaught exceptions are handled in shutdown hooks just as in any other thread, by invoking the uncaughtException method of the thread's ThreadGroup object. The default implementation of this method prints the exception's stack trace to System.err and terminates the thread; it does not cause the virtual machine to exit or halt.
- Kill pid (注:在使用kill -9 pid时,是不会被调用的)
In rare circumstances the virtual machine may abort, that is, stop running without shutting down cleanly. This occurs when the virtual machine is terminated externally, for example with the SIGKILL signal on Unix or the TerminateProcess call on Microsoft Windows. The virtual machine may also abort if a native method goes awry by, for example, corrupting internal data structures or attempting to access nonexistent memory. If the virtual machine aborts then no guarantee can be made about whether or not any shutdown hooks will be run.
JAVA DEMO
- 正常退出
package com.sparrow.hook;
/**
* Created by harryy on 2018/5/21.
*/
public class NormalExitHook {
public static void main(String[] args) {
Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
@Override
public void run() {
System.out.println("Execute Hook.....");
}
}));
System.out.println("do something");
}
}
cd /d/sparrow/sparrow-shell/sparrow-test/src/test/java/com/sparrow/hook
$ javac -encoding utf8 NormalExitHook.java
cd /d/sparrow/sparrow-shell/sparrow-test/src/test/java //注意一定要回到源码目录
java com.sparrow.hook.NormalExitHook
do something
Execute Hook.....
OOM
package com.sparrow.hook;
/**
* Created by harry on 2018/5/21.
* <p>
* -Xmx20M
*/
public class OutOfMemoryHook {
public static void main(String[] args) {
Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
@Override
public void run() {
System.out.println("Execute Hook.....");
}
}));
byte[] b = new byte[500 * 1024 * 1024];
//死循环保证不正常退出
while (true){}
}
}
cd /d/sparrow/sparrow-shell/sparrow-test/src/test/java/com/sparrow/hook
$ javac -encoding utf8 OutOfMemoryHook.java
cd /d/sparrow/sparrow-shell/sparrow-test/src/test/java
java -Xmx20M com.sparrow.hook.OutOfMemoryHook
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at com.sparrow.hook.OutOfMemoryHook.main(OutOfMemoryHook.java:16)
Execute Hook.....
Uncatch Exception
package com.sparrow.hook;
/**
* Created by harry on 2018/5/21.
*/
public class UncacheExceptionHook {
public static void main(String[] args) {
Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
@Override
public void run() {
System.out.println("Execute Hook.....");
}
}));
//运行时异常
int i=1/0;
//死循环保证不正常退出
while (true) {
}
}
}
cd /d/sparrow/sparrow-shell/sparrow-test/src/test/java/com/sparrow/hook
$ javac -encoding utf8 UncatchExceptionHook.java
cd /d/sparrow/sparrow-shell/sparrow-test/src/test/java
$ java com.sparrow.hook.UncatchExceptionHook
Exception in thread "main" java.lang.ArithmeticException: / by zero
at com.sparrow.hook.UncatchExceptionHook.main(UncatchExceptionHook.java:15)
Execute Hook.....
CTRL+C
package com.sparrow.hook;
/**
* Created by harry on 2018/5/21.
* <p>
* JAVA_HOME:D:\Java\jdk1.8.0_91
* <p>
* CLASSPATH:.;%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tools.jar;
*/
public class CtrlCHook {
public static void main(String[] args) {
Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
@Override
public void run() {
System.out.println("Execute Hook.....");
}
}));
System.out.println("do something");
System.out.println("press ctrl+c");
//死循环保证不正常退出
while (true) {
}
}
}
cd /d/sparrow/sparrow-shell/sparrow-test/src/test/java/com/sparrow/hook
$ javac -encoding utf8 CtrlCHook.java
cd /d/sparrow/sparrow-shell/sparrow-test/src/test/java
$ java com.sparrow.hook.CtrlCHook
do something
press ctrl+c
Execute Hook.....
KILL
$ kill -l
1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP
6) SIGABRT 7) SIGEMT 8) SIGFPE 9) SIGKILL 10) SIGBUS
11) SIGSEGV 12) SIGSYS 13) SIGPIPE 14) SIGALRM 15) SIGTERM
16) SIGURG 17) SIGSTOP 18) SIGTSTP 19) SIGCONT 20) SIGCHLD
21) SIGTTIN 22) SIGTTOU 23) SIGIO 24) SIGXCPU 25) SIGXFSZ
26) SIGVTALRM 27) SIGPROF 28) SIGWINCH 29) SIGPWR 30) SIGUSR1
31) SIGUSR2 32) SIGRTMIN 33) SIGRTMIN+1 34) SIGRTMIN+2 35) SIGRTMIN+3
36) SIGRTMIN+4 37) SIGRTMIN+5 38) SIGRTMIN+6 39) SIGRTMIN+7 40) SIGRTMIN+8
41) SIGRTMIN+9 42) SIGRTMIN+10 43) SIGRTMIN+11 44) SIGRTMIN+12 45) SIGRTMIN+13
46) SIGRTMIN+14 47) SIGRTMIN+15 48) SIGRTMIN+16 49) SIGRTMAX-15 50) SIGRTMAX-14
51) SIGRTMAX-13 52) SIGRTMAX-12 53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9
56) SIGRTMAX-8 57) SIGRTMAX-7 58) SIGRTMAX-6 59) SIGRTMAX-5 60) SIGRTMAX-4
61) SIGRTMAX-3 62) SIGRTMAX-2 63) SIGRTMAX-1 64) SIGRTMAX
package com.sparrow.hook;
/**
* Created by harry on 2018/5/21.
*/
public class KillHook {
public static void main(String[] args) {
Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
@Override
public void run() {
System.out.println("execute Hook.....");
}
}));
System.out.println("do something");
//死循环保证不正常退出
while (true) {
}
}
}
cd /d/sparrow/sparrow-shell/sparrow-test/src/test/java/com/sparrow/hook
$ javac -encoding utf8 KillHook.java
cd /d/sparrow/sparrow-shell/sparrow-test/src/test/java
$ java com.sparrow.hook.KillHook
do something
$ ps aux |grep java
9372 8888 9372 6436 pty0 197611 18:47:47 /c/Program Files/Java/jdk1.8.0_121/bin/java
kill -SIGHUP 9372
$ java com.sparrow.hook.KillHook
do something
Hangup
KILL 指令,并未执行hook,其他sign 测试,感兴越的朋友可以自行测试