java 使用的钩子_Java 钩子程序
簡介
觸發的時機有:
當所有的非deamon線程(守護線程)結束, 或者調用了Systrem.exit()方法 而導致的程序正常的退出
JVM收到需要關閉自己的信號(比如SIGINT、SIGTERM等,但像SIGKILL,JVM就沒有機會去處理了),也或者發生如系統關閉這種不可阻擋的事件。
對于addShutdownHook中的鉤子代碼,也是有一些要注意的地方,下面列舉幾點:
關閉鉤子可以注冊多個,在關閉JVM時就會起多個線程來運行鉤子。通常來說,一個鉤子就足夠了,但如果需要啟用多個鉤子,就需要注意并發帶來的問題。
鉤子里也要注意對異常的處理,如果不幸拋出了異常,那么鉤子的執行序列就會被終止。
在鉤子運行期間,工作線程也在運行,需要考慮到工作線程是否會對鉤子的執行帶來影響
鉤子里的代碼盡可能簡潔,否則當像系統關閉等情景可能鉤子來不及運行完JVM就被退出了。
信號觸發
使信號觸發JVM的鉤子程序
public class HookTest {
public static void main(String[] args) {
Runtime.getRuntime().addShutdownHook(new Hook());
while(true){}
}
static class Hook extends Thread{
@Override
public void run() {
System.out.println("Hook execute!!!");
}
}
}
運行鉤子程序
nohup java HookTest &
關閉程序
kill HookTest_PID
我們可以在nohup程序中看到Hook execute!!!輸出
我從JVMs and kill signals看到一篇博客, 這個上面總結了哪些信號會導致JVM運行Hook
signal shutdown runs hook exit code comment
default (15) yes yes 143 SIGTERM is the default unix kill signal
0 no - -
1 (SIGHUP) yes yes 129
2 (SIGINT) yes yes 130 SIGINT is the signal sent on ^C
3 (SIGQUIT) no - - 觸發 JVM dump threads / stack-traces
4 (SIGILL) yes no 134 觸發 JVM 輸出一個 core dump 文件, 同時abort on trap 6
5 yes no 133 Makes the JVM exit with "Trace/BPT trap: 5"
6 (SIGABRT) yes no 134 Makes the JVM exit with "Abort trap: 6"
7 yes no 135 Makes the JVM exit with "EMT trap: 7"
8 (SIGFPE) yes no 134 Makes the JVM write a core dump and abort on trap 6
9 (SIGKILL) yes no 137 The JVM is forcibly killed (exits with "Killed: 9")
10 (SIGBUS) yes no 134 Emulates a "Bus Error"
11 (SIGSEGV) yes no 134 Emulates a "Segmentation fault"
12 yes no 140 Makes the JVM exit with "Bad system call: 12"
13 no - -
14 yes no 142 Makes the JVM exit with "Alarm clock: 14"
15 (SIGTERM) yes yes 143 This is the default unix kill signal
16 no - -
17 no - 145 Stops the application (sends it to the background), same as ^Z
18 no - 146 Stops the application (sends it to the background), same as ^Z
19 no - -
20 no - -
21 no - 149 Stops the application (sends it to the background), same as ^Z
22 no - 150 Stops the application (sends it to the background), same as ^Z
23 no - -
24 yes no 152 Makes the JVM exit with "Cputime limit exceeded: 24"
25 no - -
26 yes no 154 Makes the JVM exit with "Virtual timer expired: 26"
27 yes no 155 Makes the JVM exit with "Profiling timer expired: 27"
28 no - -
29 no - -
30 yes no 158 Makes the JVM exit with "User defined signal 1: 30"
31 yes no 134 Makes the JVM exit on Segmentation fault
內存溢出觸發
測試JVM棧溢出后調用鉤子程序
public class HookTest {
public static void main(String[] args) {
Runtime.getRuntime().addShutdownHook(new Hook());
exec();
}
public static void exec() {
exec();
}
static class Hook extends Thread{
@Override
public void run() {
System.out.println("Hook execute!!!");
}
}
}
運行后輸出為
D:\testOOM>java HookTest
Exception in thread "main" java.lang.StackOverflowError
at HookTest.exec(HookTest.java:9)
at HookTest.exec(HookTest.java:9)
at HookTest.exec(HookTest.java:9)
at HookTest.exec(HookTest.java:9)
...
at HookTest.exec(HookTest.java:9)
at HookTest.exec(HookTest.java:9)
at HookTest.exec(HookTest.java:9)
at HookTest.exec(HookTest.java:9)
at HookTest.exec(HookTest.java:9)
at HookTest.exec(HookTest.java:9)
at HookTest.exec(HookTest.java:9)
at HookTest.exec(HookTest.java:9)
at HookTest.exec(HookTest.java:9)
at HookTest.exec(HookTest.java:9)
at HookTest.exec(HookTest.java:9)
Hook execute!!!
D:\testOOM>
為了測試在更加復雜的環境下, Hook的使用情況, 看下面的測試代碼
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
public class HookTest {
private static Map cache = new HashMap<>();
public static void main(String[] args) {
cache.put("abc", "abc");
Runtime.getRuntime().addShutdownHook(new Hook());
byte[] bytes = new byte[1024 * 1024 *1024 * 1024];
}
static class Hook extends Thread{
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(LocalDateTime.now());
System.out.println(" freeMemory : " + Runtime.getRuntime().freeMemory());
System.out.println(" maxMemory : " + Runtime.getRuntime().maxMemory());
System.out.println(" totalMemory : " + Runtime.getRuntime().totalMemory());
System.out.println(" currentThread name : " + Thread.currentThread().getName());
System.out.println(" cache size : " + cache.size());
cache.put(LocalDateTime.now().toString(), LocalDateTime.now().toString());
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
運行后的輸出結果為
ζ java HookTest
2016-07-09T16:12:12.479
freeMemory : 155922512
maxMemory : 2375024640
totalMemory : 160956416
currentThread name : Thread-0
cache size : 1
2016-07-09T16:12:13.480
freeMemory : 155922512
maxMemory : 2375024640
totalMemory : 160956416
currentThread name : Thread-0
cache size : 2
2016-07-09T16:12:14.480
freeMemory : 155922512
maxMemory : 2375024640
totalMemory : 160956416
currentThread name : Thread-0
cache size : 3
2016-07-09T16:12:15.480
freeMemory : 155922512
maxMemory : 2375024640
totalMemory : 160956416
currentThread name : Thread-0
cache size : 4
...
正常結束觸發
測試程序正常結束后也會調用鉤子程序
public class HookTest {
public static void main(String[] args) {
Runtime.getRuntime().addShutdownHook(new Hook());
}
static class Hook extends Thread{
@Override
public void run() {
System.out.println("Hook execute!!!");
}
}
}
運行結果為
D:\testOOM>java HookTest
Hook execute!!!
D:\testOOM>
調用exit()觸發
public class HookTest {
public static void main(String[] args) {
Runtime.getRuntime().addShutdownHook(new Hook());
System.exit(0);
System.out.println("Main over");
}
static class Hook extends Thread{
@Override
public void run() {
System.out.println("Hook execute!!!");
}
}
}
運行結果為
D:\testOOM>java HookTest
Hook execute!!!
D:\testOOM>
不被觸發
再google上找到了一篇這樣的文章Know the JVM Series: Shutdown Hooks里面介紹了鉤子程序在什么情況下不會執行
盡管上面列舉出了N多觸發鉤子程序的示例, 但是并不保證這個鉤子程序總是能被觸發執行的, 例如
JVM內部發生錯誤, 可能還沒有來得及觸發鉤子程序, JVM就掛掉了(JVM 發生內部錯誤, 有沒有日志呢?)
還有上面我們給出的那個信號表, 如果操作系統發送出上面的信號的話, 同樣的, JVM沒有執行鉤子程序就退出了
還有調用Runime.halt()函數也不會執行鉤子程序
還有一種情況是, 當操作系統向進程發送一個SIGTERM信號之后, 如果進程沒有在指定的時間之內關閉, 那么操作系統會強制將該進程殺掉, 如此一來鉤子程序也不會得到完整的執行(因為鉤子程序可能執行到一半就被操作系統殺死了). 因此不管是這篇文章還是JDK API都推薦不要在鉤子程序里寫復雜的業務邏輯, 避免產生死鎖或者產生長時間的IO操作, 盡可能快地讓鉤子程序執行完畢.
Will shutdown hooks be run if the VM crashes?
If the VM crashes due to an error in native code then no guarantee can be made about whether or not the hooks will be run.
哎,, 怎么著才能監控JVM掛掉的信息呢?
總結
以上是生活随笔為你收集整理的java 使用的钩子_Java 钩子程序的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 从QQ2010看腾讯
- 下一篇: 最新泛微java面试题及答案