您好,登錄后才能下訂單哦!
本篇內容主要講解“JVM鉤子函數的使用場景介紹”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“JVM鉤子函數的使用場景介紹”吧!
一、問題引入
背景
原始思路
二、JVM鉤子使用場景
正常關閉
異常關閉
強制關閉
三、回歸問題
在編寫一個需要持續在后臺運行的程序的時候遇到了這樣的場景:我的程序在主函數中創建了一個線程池周期性地執行任務,我希望主線程和線程池都持續運行,但如果收到外部的關閉信號時,主線程和線程池也都能同時退出。想到的就是程序結束的時候需要有一個stop()方法去手動關閉線程池,但是怎么控制這個stop()方法在我想要的時候調用,以什么形式去接收外部的關閉信號也成了需要考慮的問題。
最開始的嘗試是我將程序的運行和停止分別用"start"和"stop"兩種狀態表示,然后用一個狀態文件state去記錄當前的狀態(程序啟動時默認是"start"),如果想要關閉這個正在運行的程序,就去修改狀態文件state,將里面內容變為"stop"。同時在主函數中打開這個狀態文件,循環監聽里面的內容,如果發現變為"stop",就去調用stop()方法執行關閉邏輯。按照這個思路,我寫了一個簡單的程序在IDEA中測試了一下效果,發現是可行的。但是當我將程序打包,在mac系統上運行jar包進行測試的時候,不知什么原因,程序總是讀到state文件剛打開時的內容,不能檢測到state文件的變化,無法按我設想的方式進行關閉。因此只能另想辦法。
無意間看見JVM鉤子函數的介紹,發現這可能正是我想要的,于是趕緊拿來試一試。
JVM關閉的情況如下圖所示分為三類,第一種是正常的關閉,第二種是異常關閉的情況,第三種是強制關閉的情況。
JVM鉤子函數對于前兩種方式都可以進行優雅的關閉,但是對最后一種強制關閉就不起作用了。
下面我會根據這三種JVM關閉過程進行簡單演示。
代碼如下:
public class TestJVMHook { public static void main(String[] args) { Runtime.getRuntime().addShutdownHook(new Thread(()-> stop() )); start(); System.out.println("===程序正常結束==="); } public static void start() { System.out.println("===調用start()方法==="); } public static void stop() { System.out.println("===調用stop()方法==="); } }
運行結果:
===調用start()方法===
===程序正常結束===
===調用stop()方法===
可以看到,在鉤子函數中聲明了stop()方法,然后程序正常結束后會自動調用鉤子函數。
異常關閉分為OOM和RuntimeException兩種情況,我用除數為0的運行時異常來演示。
代碼如下:
public class TestJVMHook { public static void main(String[] args) { Runtime.getRuntime().addShutdownHook(new Thread(()-> stop() )); start(); int res = 10/0; System.out.println("===程序結束==="); } public static void start() { System.out.println("===調用start()方法==="); } public static void stop() { System.out.println("===調用stop()方法==="); } }
運行結果:
===調用start()方法===
===調用stop()方法===
Exception in thread "main" java.lang.ArithmeticException: / by zero
at com.example.TestJVMHook.main(TestJVMHook.java:9)
可以看到執行"10/0"時發生運行時異常,并不會正常打印下一行語句,但仍然會自動調用鉤子函數中stop()方法。
這里我們啟動一個循環程序,然后手動去關閉它。
代碼如下:
public class TestJVMHook { public static void main(String[] args) throws InterruptedException { Runtime.getRuntime().addShutdownHook(new Thread(()-> stop() )); int count = 1; start(); while(true){ System.out.println("循環計數器"+(count++)); Thread.sleep(5*1000); } } public static void start() { System.out.println("===調用start()方法==="); } public static void stop() { System.out.println("===調用stop()方法==="); } }
啟動后查看進程id,然后通過"kill -9 <pid>"強制關閉:
運行結果:
還是上面那段代碼,再次啟動,采用"kill <pid>"關閉:
發現通過"kill "正常關閉可以有效調用鉤子函數,但是"kill -9 "強制關閉則不會調用鉤子函數。
經過一系列測試,驗證了JVM鉤子函數確實可以實現我想要的資源關閉效果。由于我的程序是一個循環程序,需要手動關閉,因此可以在關閉程序的腳本中通過kill pid的方式進行鉤子函數的調用。
到此,相信大家對“JVM鉤子函數的使用場景介紹”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。