我只是不明白为什么必须使用 Runtime.addShutdownHook。如果您想在 jvm 退出时进行一些清理,为什么不重载守护程序类的 finalize 方法。与 finalize 方法相比,使用关闭挂钩有什么优势。
还有一个已弃用的函数 runFinalizersOnExit。如果我将其设置为 false,我相信终结器将不会运行。这与 java 保证终结器总是在垃圾收集之前运行相矛盾。
我只是不明白为什么必须使用 Runtime.addShutdownHook。如果您想在 jvm 退出时进行一些清理,为什么不重载守护程序类的 finalize 方法。与 finalize 方法相比,使用关闭挂钩有什么优势。
还有一个已弃用的函数 runFinalizersOnExit。如果我将其设置为 false,我相信终结器将不会运行。这与 java 保证终结器总是在垃圾收集之前运行相矛盾。
无法保证终结器将永远运行。finalize()当对象被垃圾回收时调用。但是当程序运行时,垃圾收集器可能不会收集任何东西。
相比之下,当 jvm 正常退出时会运行关闭挂钩。所以即使这也不是 100% 的保证,但它非常接近。只有少数情况下关闭挂钩不运行。
编辑 我查找了未执行关闭挂钩的边缘情况
已执行关闭挂钩:
未执行关闭挂钩:
关于您的查询
如果你想在 jvm 退出时进行一些清理,为什么不重载 daemon 类的 finalize 方法
我从这篇文章中找到了很好的信息
finalize()在垃圾收集器回收对象之前调用。JVM 不保证何时调用此方法。
finalize()如果对象从 finalize 方法中恢复自身,则 GC 线程仅调用一次,而不是 finalize 将不再被调用。
在您的应用程序中,您可能有一些活动对象,它们永远不会调用垃圾收集。
GC线程忽略finalize方法抛出的任何异常
System.runFinalization(true)和Runtime.getRuntime().runFinalization(true)方法增加了调用finalize()方法的概率,但现在这两种方法已被弃用。由于缺乏线程安全性和可能产生死锁,这些方法非常危险。
根据 oracle文档,回到 shutdownHooks
public void addShutdownHook(Thread hook) 注册一个新的虚拟机关闭钩子。
Java 虚拟机关闭以响应两种事件:
但即使是甲骨文文档也引用了
关闭挂钩也应该快速完成它们的工作。当程序调用 exit 时,期望虚拟机将立即关闭并退出。
在极少数情况下,虚拟机可能会中止,即在没有干净关闭的情况下停止运行
考虑到这两种方法的缺点,您应该遵循以下方法
不要依赖finalize()或shutdown hooks释放应用程序中的关键资源。
适当使用try{} catch{} finally{}块并在块中释放关键资源 finally(}。在finally{}块中释放资源期间,catchException和Throwable.