源码点击 study 查看
Shutdown hook是什么
Shutdown hook是Jvm敞开的钩子,是通过Runtime#addShutdownHook(Thread hook)办法来实现的,依据api是注解可知它就是一系例的已初始化但尚未执行的线程对象。咱们能够通过向Jvm注册一个钩子,实现在程序退出时敞开资源、平滑退出的性能。所谓的优雅停机也能够这么搞。
Jvm敞开的形式
程序只有在失常敞开和异样敞开的状况下才会调用钩子函数坐一些开头的工作,如果是强制敞开的则不会调用,强制敞开间接无磋商终止jvm过程,不给jvm喘息的机会。
应用敞开钩子的注意事项
- 敞开钩子实质上是一个线程(也称为Hook线程),对于一个JVM中注册的多个敞开钩子它们将会并发执行,所以JVM并不保障它们的执行程序;因为是并发执行的,那么很可能因为代码不当导致呈现竞态条件或死锁等问题,为了防止该问题,强烈建议在一个钩子中执行一系列操作。
- Hook线程会提早JVM的敞开工夫,这就要求在编写钩子过程中必须要尽可能的缩小Hook线程的执行工夫,防止hook线程中呈现耗时的计算、期待用户I/O等等操作。
- 敞开钩子执行过程中可能被强制打断,比方在操作系统关机时,操作系统会期待过程进行,期待超时,过程仍未进行,操作系统会强制的杀死该过程,在这类状况下,敞开钩子在执行过程中被强制停止。
- 在敞开钩子中,不能执行注册、移除钩子的操作,JVM将敞开钩子序列初始化结束后,不容许再次增加或者移除曾经存在的钩子,否则JVM抛出 IllegalStateException。
- 不能在钩子调用System.exit(),否则卡住JVM的敞开过程,然而能够调用Runtime.halt()。
- Hook线程中同样会抛出异样,对于未捕获的异样,线程的默认异样处理器解决该异样,不会影响其余hook线程以及JVM失常退出
简略例子(具体可看源码)
1.业务要敞开的资源
public class StudyResource implements AutoCloseable { @Override public void close() throws Exception { System.out.println("执行我的项目资源敞开操作"); }}
2.自定义钩子
/** * @author: lixiaoshuang * @create: 2020-11-25 20:48 **/public class StudyShtudownHook extends Thread { private static final StudyShtudownHook INSTANCE = new StudyShtudownHook(); /** * 须要敞开的钩子汇合,能够将我的项目中的资源敞开操作都放在这里 */ private final Set<AutoCloseable> autoCloseableHashSet = new HashSet<>(); private StudyShtudownHook() { } public static StudyShtudownHook getInstance() { return INSTANCE; } public void registerAutoCloseable(final AutoCloseable autoCloseable) { autoCloseableHashSet.add(autoCloseable); } @Override public void run() { this.closeAll(); } @SneakyThrows private void closeAll() { for (AutoCloseable autoCloseable : autoCloseableHashSet) { autoCloseable.close(); } }}
- 向jvm注册钩子
public class JvmHookDemo { public static void main(String[] args) throws InterruptedException { //本人实现的钩子 StudyShtudownHook instance = StudyShtudownHook.getInstance(); //将须要敞开的资源放到钩子里 StudyResource studyResource = new StudyResource(); instance.registerAutoCloseable(studyResource); //向jvm注册钩子 Runtime.getRuntime().addShutdownHook(instance); System.out.println("执行业务逻辑。。。。"); Thread.sleep(5000); System.out.println("业务逻辑处理完毕。。。。"); }}
执行这段代码后输入:
执行业务逻辑。。。。业务逻辑处理完毕。。。。
执行我的项目资源敞开操作