一起学并发编程 - 钩子函数(shutdownHook)
shutdownHook是一種特殊的結構,它允許開發人員插入JVM關閉時執行的一段代碼。這種情況在我們需要做特殊清理操作的情況下很有用
<!-- more -->
用途
在Jboss,Jetty等容器中都可以看到shutdownHook的身影,例如在服務優雅下線一文中的spring-boot-starter-actuator就會觸發shutdownHook...
- Application正常退出,在退出時執行特定的業務邏輯,或者關閉資源等操作。
- 虛擬機非正常退出,比如用戶按下ctrl+c、OOM宕機、操作系統關閉(kill pid)等。在退出時執行必要的挽救措施。
用法
正常退出
public class ShutdownHook {public static void main(String[] args) throws InterruptedException {Runtime.getRuntime().addShutdownHook(new Thread(() -> {try (FileWriter fw = new FileWriter("hook.log")) {// 假設記錄日志/或者發送消息fw.write("完成銷毀操作,回收內存! " + (new Date()).toString());System.out.println("退出程序...");} catch (IOException e) {e.printStackTrace();}}));IntStream.range(0, 10).forEach(i -> {try {System.out.println("正在工作...");Thread.sleep(2_000L);} catch (InterruptedException e) {e.printStackTrace();}});} }當我們運行上面的代碼時,會看到在完成main方法的執行時JVM調用shutdownHook。
正在工作... ... 正在工作... 退出程序...
kill pid方式
注意事項
雖然編寫一個shutdownHook很簡單,但是需要了解shutdownHook后面的內部部件才能正確使用。因此,在后續中,將探討shutdownHook設計背后的一些陷阱。
應用程序無法保證shutdownHook總是運行的
如JVM由于某些內部錯誤而崩潰,或(Unix / Linux中的kill -9)或TerminateProcess(Windows)),那么應用程序需要立即終止而不會甚至等待任何清理活動。除了上述之外,還可以通過調用Runime.halt()方法來終止JVM,而阻止shutdownHook運行。
shutdownHook可以在完成前強行停止
雖然shutdownHook開始執行,但是在操作系統關閉的情況下,任然可以在完成之前終止它。在這種情況下,一旦SIGTERM被提供,O/S等待一個進程終止指定的時間。如果進程在該時間限制內沒有終止,則O/S通過發出SIGTERM(或Windows中的對等方)強制終止進程。所以有可能這是在shutdownHook中途執行時發生的。
因此,建議謹慎地編寫shutdownHook,確保它們快速完成,并且不會造成死鎖等情況。另外特別注意的是,不應該執行長時間計算或等待用戶I/O操作在鉤子。
可以有多個shutdownHook,但其執行順序無法保證
public void addShutdownHook(Thread hook) {SecurityManager sm = System.getSecurityManager();if (sm != null) {sm.checkPermission(new RuntimePermission("shutdownHooks"));}ApplicationShutdownHooks.add(hook); } class ApplicationShutdownHooks {/* The set of registered hooks */private static IdentityHashMap<Thread, Thread> hooks;static synchronized void add(Thread hook) {if(hooks == null)throw new IllegalStateException("Shutdown in progress");if (hook.isAlive())throw new IllegalArgumentException("Hook already running");if (hooks.containsKey(hook))throw new IllegalArgumentException("Hook previously registered");hooks.put(hook, hook);} }通過源碼發現,可以注冊多個shutdownHook。但是因為它是存儲在IdentityHashMap中的,JVM并不能保證其執行順序。但是可以同時執行所有的shutdownHook
關閉順序開始后,無法注冊/取消注冊shutdownHook
一旦關閉順序是由JVM發起的,將不在允許添加或刪除任何現有的shutdownHook,否則拋出IllegalStateException異常。
關閉順序開始后,只能由Runtime.halt()停止
關閉順序開始后,只能通過Runtime.halt()(強制終止JVM),可以停止關閉順序的執行(外部影響除外,如SIGKILL)。
使用shutdownHook需要安全權限
如果我們使用Java Security Managers,則執行添加/刪除shutdownHook的代碼需要在運行時具有shutdownHooks權限。否則會導致SecurityException。
參考:http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/Runtime.html#addShutdownHook(java.lang.Thread) "官方文檔")
- 說點什么
全文代碼:https://gitee.com/battcn/battcn-concurent/tree/master/Chapter1-1/battcn-thread/src/main/java/com/battcn/chapter10
- 個人QQ:1837307557
- battcn開源群(適合新手):391619659
微信公眾號:battcn(歡迎調戲)
總結
以上是生活随笔為你收集整理的一起学并发编程 - 钩子函数(shutdownHook)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 如何为编程爱好者设计一款好玩的智能硬件(
- 下一篇: 腾讯会议app怎么录屏(腾讯视频VIP会