在Linux上一般會經過kill -9 pid的方式強制將某個進程殺掉,這種方式簡單高效,所以不少程序的中止腳本常常會選擇使用kill -9 pid的方式。數據庫
不管是Linux的Kill -9 pid仍是windows的taskkill /f /pid強制進程退出,都會帶來一些反作用:對應用軟件而言其效果等同於忽然掉電,可能會致使以下一些問題:windows
Java的優雅停機一般經過註冊JDK的ShutdownHook來實現,當系統接收到退出指令後,首先標記系統處於退出狀態,再也不接收新的消息,而後將積壓的消息處理完,最後調用資源回收接口將資源銷燬,最後各線程退出執行。緩存
一般優雅退出須要有超時控制機制,例如30S,若是到達超時時間仍然沒有完成退出前的資源回收等操做,則由停機腳本直接調用kill -9 pid,強制退出。異步
要實現Netty的優雅退出,首先須要瞭解通用Java進程的優雅退出如何實現。下面咱們先講解下優雅退出的實現原理,並結合實際代碼進行講解。最後看下如何實現Netty的優雅退出。ide
信號是在軟件層次上對中斷機制的一種模擬,在原理上,一個進程收到一個信號與處理器收到一箇中斷請求能夠說是同樣的,它oop
是進程間一種異步通訊的機制。以Linux的kill命令爲例,kill -s SIGKILL pid (即kill -9 pid) 當即殺死指定pid的進程,SIGKILL就是發送給pid進程的信號。測試
信號具備平臺相關性,Linux平臺支持的一些終止進程信號以下所示:操作系統
Windows平臺存在一些差別,它的一些信號舉例以下:SIGINT(Ctrl+C中斷)、SIGILL、SIGTERM (kill發出的軟件終止)、SIGBREAK (Ctrl+Break中斷)。線程
信號選擇:爲了避免干擾正常信號的運做,又能模擬Java異步通知,在Linux上咱們須要先選定一種特殊的信號。經過查看信號列表上的描述,發現 SIGUSR1 和 SIGUSR2 是容許用戶自定義的信號,咱們能夠選擇SIGUSR2,爲了測試方便,在Windows上咱們能夠選擇SIGINT。code
首先看下通用的Java進程優雅退出的流程圖:
Signal sig = new Signal(getOSSignalType());
private String getOSSignalType() { return System.getProperties().getProperty("os.name"). toLowerCase().startsWith("win") ? "INT" : "USR2"; }
判斷是不是windows操做系統,若是是則選擇SIGINT,接收Ctrl+C中斷的指令;不然選擇USR2信號,接收SIGUSR2(等價於kill -12 pid)指令。
Signal.handle(sig, shutdownHandler);
其中shutdownHandler實現了SignalHandler接口的handle(Signal sgin)方法,代碼示例以下:
private void invokeShutdownHook() { Thread t = new Thread(new ShutdownHook(), "ShutdownHook-Thread"); Runtime.getRuntime().addShutdownHook(t); }
Runtime.getRuntime().exit(0);
虛擬機退出時,底層會自動檢測用戶是否註冊了ShutdownHook任務,若是有,則會自動將ShutdownHook線程拉起,執行它的Run方法,用戶只須要在ShutdownHook中執行資源釋放操做便可,示例代碼以下:
class ShutdownHook implements Runnable { @Override public void run() { System.out.println("ShutdownHook execute start..."); System.out.print("Netty NioEventLoopGroup shutdownGracefully..."); try { TimeUnit.SECONDS.sleep(10);//模擬應用進程退出前的處理操做 } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("ShutdownHook execute end..."); System.out.println("Sytem shutdown over, the cost time is 10000MS"); } }
下面咱們在Windows環境中對通用的Java優雅退出程序進行測試,打開CMD控制檯,拉起待測試程序,以下所示:
啓動進程:
查看線程信息,發現註冊的ShutdownHook線程沒有啓動,符合預期: