Hook作爲一種回調方式,廣泛應用於軟件中。
從Java 1.3開始,JVM的Runtime也提供了hook的機制,即shutdown hook。提供給出shutdown hook,在退出JVM的時候,能夠執行shutdown hook中定義的必要操作。
1. Runtime的Shutdown Hook的特性
- 可以註冊多個hook,每個都是一個獨立的線程
- 如果有多個Hook,Hook線程之間是沒有同步的,線程運行的時序是不可預測的
- 一旦開始執行Shutdown Hook,即無法再註冊或刪除其他hook
- 正在執行的Shutdown Hooks,還可能被外部的SIGTERM信號強制停止
- 正在執行的Shutdown Hooks,在JVM內部只能通過調用Runtime.halt()停止hook的執行
- 如果JVM啓用了Java Security Managers,則執行Shutdown Hook需要shutdownHooks權限
2. 註冊Shutdown Hook的方式
Runtime.getRuntime().addShutdownHook(
new Thread(new Runnable() {
@Override
public void run() {
abc;...
}
});
);
在Java 8以後,還可以採用如下流式方式註冊hook:
Runtime.getRuntime().addShutdownHook(
new Thread( () -> {
abc;...
});
);
3. 通常,JVM退出的方式有如下
- 程序正常結束,JVM最後執行System.exit(0);
- 程序異常結束,JVM最後執行System.exit(1);
- 程序被外部請求中斷退出,如用戶執行CTRL+C
對於上述的JVM退出方式,Runtime的shutdown hook都將被執行,然後才真正退出JVM。
但是,Runtime的Shutdown Hook在如下情況下,無法被執行:
- JVM crashes
- 外部中斷請求發出了kill -9 <PID>的命令
- 程序執行過程中,主動調用了Runtime.halt();
4. 補充說明SIGTERM信號
kill <PID>發出的SIGTERM信號,該信號會陷入(trappable),正在運行的進程執行收尾操作後,響應該信號停止。
- kill -2 <PID>等價於CTRL+C,即發出SIGINT信號,該信號會陷入,正在運行的進程執行收尾操作後,響應該信號停止
- kill -9 <PID>發出SIGKILL信號,該信號不會陷入(not trappable),正在運行的進程直接被終止,沒有機會執行收尾操作