public class Test { public static void main(String[] args){ System.out.println("1: Main start"); Thread mainThread = Thread.currentThread(); //注冊一個 ShutdownHook ShutdownSampleHook thread=new ShutdownSampleHook(mainThread); Runtime.getRuntime().addShutdownHook(thread); try { Thread.sleep(30*1000); } catch (InterruptedException e) { System.out.println("3: mainThread get interrupt signal."); } System.out.println("4: Main end"); } } class ShutdownSampleHook extends Thread { private Thread mainThread; @Override public void run() { System.out.println("2: Shut down signal received."); mainThread.interrupt();//給主線程發送一個中斷信號 try { mainThread.join(); //等待 mainThread 正常運行完畢 } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("5: Shut down complete."); } public ShutdownSampleHook(Thread mainThread) { this.mainThread=mainThread; } }
關於 mainThread.interrupt() 方法的說明, 該方法將給主線程發送一個中斷信號. 如果主線程沒有進入阻塞狀態, interrupt() 其實沒有什么作用; 如果主線程處於阻塞狀態, 該線程將得到一個 InterruptedException 異常. 在調用 mainThread.join() 或 mainThread.wait() 之前, 仍可以通過調用 mainThread.interrupted() 來清除中斷信號.
一個線程有三種進入阻塞狀態的方法, 分別是調用 Thread.wait() 或 Thread.join() 或 Thread.sleep().
正常情況下, 程序需要運行 30 秒, 程序的輸出是:
如果在程序啟動后, 按下 Ctrl+C, 程序很快就結束了, 最終的輸出是:
spring的shutdownhook是在AbstractApplicationContext.registerShutdownhook方法內,可以通過springapplication的set方法取消這個鈎子。createApplicationContext這個方法內部通過反射,構建了ConfigurableApplicationContext的實例,是AbstractApplicationContext的子類,因此會調用到AbstractApplicationContext.registerShutdownhook方法。
dubbo在AbstractConfig的靜態代碼塊添加了一個鈎子,鈎子內部調用了ProtocolConfig的destroyAll靜態方法,所以無法關閉鈎子,也無法通過繼承等方式在這個流程去控制鈎子。
唯一可能可以的方式是通過繼承dubboProtocol類,實現dubboProtocol類的destory方法,更改服務注冊以及關閉的邏輯,然后在ProtocolConfig類中指定協議為這個繼承類。由於太麻
煩而且也不是很合理所以沒有繼續實踐了。
關於dubbo關閉鈎子的解決方案,下面這個鏈接有簡單介紹,思路是直接更改shutdownhook的map,將dubbo的shutdownhook過濾掉
https://blog.csdn.net/wins22237/article/details/72758644/