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/