Effective Java (2nd Edition)读书笔记-Item 7: 避免finalizers

Effective Java (2nd Edition)读书笔记-Item 7: 避免finalizers
        Finalizer是不可预知的,经常出问题的,而且是不必要的。使用它可能会导致不可预知的行为,性能降低和简洁问题。C++需要析构函数释放资源,Java是用垃圾回收器管理对象释放。Java中一般在finally中是否其他资源。
        finalizer的一个缺点是:不能保证他们在对象无用的时候立即执行。这就意味着不能在finalizer中做严格要求时间的事情。例如不要在finalizer中关闭文件。
       finalizer的执行只是垃圾回收器算法的一个主要函数。每个JVM实现都会不同。
       不要依赖finalizer来更新临界持有状态。例如不要在finalizer中释放共享资源的持有锁。
       不要受System.gc和System.runFinalizerOnExit的诱惑.它们可能会增加finalizer执行的机会,但是不能保证。System.runFinalizerOnExit和Runtime.runFinalizersOnExit只是保证finalization。
        使用finalizers会导致性能损失。在我的机器上创建和销毁一个对象的时间是5.6ns,但是使用finalizer会增加时间到2400ns.
     那么应该如何终止资源,例如文件和线程?如果仅仅是需要显式的终止方法,那么可以使用InputStream和OutputStream和java.sql.Connection的Close方法。还有就是使用java.util.Timer的Cancel方法,对于java.awt使用Graphics.dispose和Window.dispose.
     一般典型的显式终止方法是包含在try-finally中来确保结束。例如
1 //  try-finally block guarantees execution of termination method
2 Foo foo  =   new  Foo();
3 try   {
4// Do what must be done with foo
5
6}
  finally   {
7foo.terminate(); // Explicit termination method
8}
     四个类来作为显示终止方法模式的例子:FileInputStream, FileOutputStream, Timer, and Connection。
      使用finalizer的第二个合理对象是native peers。native peer是一个native对象它是通过native方法来代理正常的对象。由于native peer不是正常的对象,垃圾回收器无法知道它和在Java Peer回收的时候回收它。就需要finalizer来完成这个任务,来确保native peer不再持有临界资源。
      应该注意到,“finalizer chaining”不是自动完成的。如果一个类有一个finalizer,子类复写了它。子类必须手动调用父类的finalizer。应该包含子类的finalizer在try中,将父类的finalizer放在finally中:
//  Manual finalizer chaining
@Override  protected   void  finalize()  throws  Throwable  {
try {
 
// Finalize subclass state
}
 finally {
super.finalize();
}

}
如果子类实现复写了父类的finalizer,但是忘记了调用,父类的finalizer就不会被调用。
可以将finalizer放入一个匿名类中。匿名类的单实例叫做finalizer哨,被包含类为每个实例创建一个finalizer哨。
 1 //  Finalizer Guardian idiom
 2 public   class  Foo  {
 3// Sole purpose of this object is to finalize outer Foo object
 4private final Object finalizerGuardian = new Object() {
 5@Override protected void finalize() throws Throwable {
 6 // Finalize outer Foo object
 7}

 8}
;
 9 // Remainder omitted
10}
包含类存储了一个私有单一引用在finalizer哨中。注意,Foo类不需要finalizer,因此不用担心是否子类调用super.finalize.这种技术应该在每个具有finalizer的非final public 类中考虑。
总结:
不要使用finalizer,除非为了安全网或者终止非临界native资源。在那些使用finalizer的极少的实例中,记住要调用super.finalize。如果使用finalize作为安全网,记住从finalizer中输出无效用法的日志。最后,如果你需要关联一个finalizer到public非静态类中,考虑使用finalizer哨,它可以保证调用super.finalize失败是还是可以finalization。
In summary, don’t use finalizers except as a safety net or to terminate
noncritical native resources. In those rare instances where you do use a finalizer,
remember to invoke super.finalize. If you use a finalizer as a safety net,
remember to log the invalid usage from the finalizer. Lastly, if you need to
associate a finalizer with a public, nonfinal class, consider using a finalizer
guardian, so finalization can take place even if a subclass finalizer fails to invoke
super.finalize.

你可能感兴趣的:(Effective Java (2nd Edition)读书笔记-Item 7: 避免finalizers)