我只是不明白为什么必须使用 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
.