我同意大部分答案。
你不应该完全依赖finalize
或ShutdownHook
finalize
JVM不能保证何时调用finalize()
方法。
finalize()
只会被GC线程调用一次。如果一个对象在finalizing方法中复活,那么finalize
将不会再次被调用。
在你的应用程序中,你可能有一些活动对象,垃圾回收从未被调用。
任何由finalizing方法抛出的异常都会被GC线程忽略
System.runFinalization(true)
和Runtime.getRuntime().runFinalization(true)
方法增加了调用finalize()
方法的可能性,但现在这两个方法已经被弃用。由于缺乏线程安全性和可能导致死锁,这些方法非常危险。
shutdownHooks
public void addShutdownHook(Thread hook)
注册一个新的虚拟机关闭钩子。Java虚拟机响应两种类型的事件而关闭:
1.程序正常退出,即最后一个非守护线程退出或调用exit(等效于System.exit)方法时;
2.响应用户中断(例如键入^C)或系统范围事件(例如用户注销或系统关闭)而终止虚拟机。
关闭钩子只是一个已初始化但未启动的线程。当虚拟机开始其关闭序列时,它将以某种未指定的顺序启动所有注册的关闭钩子,并让它们并发运行。当所有钩子都完成后,如果启用了退出时终结,则会运行所有未调用的finalizer。
最后,虚拟机将停止。请注意,在关闭序列期间,守护线程将继续运行,如果通过调用exit方法来启动关闭,则非守护线程也将继续运行。
关闭钩子也应该快速完成它们的工作。当程序调用exit时,期望虚拟机会迅速关闭和退出。
但是即使Oracle文档引用了以下内容:
在极少数情况下,虚拟机可能会中止,即在没有清理关闭的情况下停止运行。
这种情况发生在虚拟机在外部被终止,例如在Unix上使用SIGKILL信号或在Microsoft Windows上使用TerminateProcess调用时。如果本机方法出现问题,例如损坏内部数据结构或尝试访问不存在的内存,则虚拟机也可能会中止。如果虚拟机中止,则无法保证是否运行任何关闭钩子。
结论:适当使用try{} catch{} finally{}块并在finally{}块中释放关键资源。在释放资源时,捕获Exception和Throwable。