java终结方法finalize()详解,以及如何正确使用

一、终结方法存在的问题:
1.终结方法通常是不可预测的,也是很危险的,一般情况下是不必要的,使用终结方法回导致行为很不稳定,降低成本及移植性问题;
2.终结方法的缺点在于不能被及时的执行,
3.终结方法的线程优先级比其应用中的其他程序的线程优先级低,。
4.不应该以来终结方法来更新重要的持久状态,例如利用终结方法来释放共享资源(比如数据库)上的永久锁,很容易让整个分布式系统垮掉
不要被System.runFinalization();和System.gc();这两个方法所诱惑,他们确实增加了终结方法 的执行机会但不保证一定会执行,唯一确保终结方法会执行的是System.runFinalizersOnExit(value);以及他臭名昭著的孪生兄弟Runtime.runFinalizersOnExit(value);,这两个方法都有致命缺陷,已经被废弃了。

5.终结方法还有一个严重的性能损失。用了终结方法创建和销毁一个对象大概慢了430倍;

6.当无法确定是否应该避免使用终结方法的时候,还有一种值得考虑的情形,如果为捕获的异常在终结过程被抛出来。那么这种异常可以忽略。并且改对象的终结过程也会终止。未捕获异常会使对象处于破坏状态,如果另一个线程企图使用这种被破坏的对象,则可能发生不确定的行为,正常情况下,未捕获的异常会使线程终止,并打印出栈的轨迹,但是,如果异常发生在终结方法,则不会如此,甚至连警告都打不出来。
二、不用写终结方法实现相同的功能
如果类的对象中封装的资源(例如文件或者线程)确实需要终止,要怎么做才能不用写终结方法呢?只需提供一个显式的终结方法。并且要求每个调用类实例的客户端在实例不再用的时候调用这个方法。
显式终止方法通常与try-finally结合起来使用,以确保及时终止。
、如何正确使用终结方法
那么终结方法有什么好处呢,他们有两种合法用途,第一种是,当对象的所有者忘记调用前面段落中建议的显式终止方法的时候,它可以充当安全网。虽然这么做不能保证中介方法会被及时调用,但是在客户端无法通过显式种植方法正常结束操作的情况下,迟一点释放资源总比永远不释放的好。但是如果终结方法发现资源还未被释放,应在日志中记录一条警告。因为这表示一个bug应该得到修复,如果要写这样的安全网终结方法,要考虑清楚额外的保护是否值得你付出额外的代价。
显示终止方法模式的示例中所示的四个类(FileInputStream,FileOutputStream,Timer和Connection) ,都具有终结方法,当他们的终止方法未能被调用的情况下,这些终结方法充当了安全网。
那么中介方法的第二种合理用途是 与对象的本地对等体有关,本地对等体是一个本地对象,普通对象通过本地方法委托给一个本地对象,因为本地对等体不是一个普通对象,所以垃圾回收器不会知道它,当他的java对等体被回收的时候它不会被回收,在本地对等体并不拥有关键资源的前提下,终结方法正是执行这项任务最合适的工具,如果本地对等体拥有必须及时终止的资源,那么该类就应该具有一个显式的终止方法,如前所述终止方法应该完成所有必要工作以便释放关键资源,终止方法可以是本地方法,或者它可以调用本地方法,
终结方法链并不会被自动执行, 如果类有终结方法,并且子类覆盖。子类必须手动调用超类的终结方法。(finally中调用)
防止子类没有手动调用超类的中介方法:为每个将被终结的对象创建一个附加对象,不是把终结方法放在要终结处理的类中,而是把终结方法放在一个匿名的类。该匿名类的单个实例被称为终结方法守卫者,外围类每个实例都会创建一个这样的守卫者,外围实力在他的私有实例域中保存这一个对其中介方法守卫者的唯一引用,因此终结方法 守卫者与外围实例可以同时启动终结过程,当守卫者被终结的时候,它执行外围实例所期望的终结行为,就好像它的终结方法是外围对象上的一个方法一样

注意:公有类Foo并没有终结方法,所以子类的终结方法时候调用super.finalize并不重要,对于每一个带有终结方法的非final公有类,都应该考虑使用这种方法
总之,除非是作为安全网,或者是为了终止本地的关键资源,否则不要用终结方法,即使用了,就要记住调用super.finalize。如果终结方法作为安全网,记得记录终结方法的非法用法,最后,如果需要把终结方法与公有费final类关联起来,请考虑使用终结方法守卫者,以确保子类未能调用super.finalize该终结方法也会被执行。





猜你喜欢

转载自blog.csdn.net/qq86673187/article/details/80943208