Effective-Java读书笔记07 Avoid finalizers 避免使用finalizers

07 Avoid finalizers 避免使用finalizers

这里说的finalizers指的是Object类提供的finalize()方法, 该方法默认是一个空方法, 作者不建议我们重写使用该方法.

protected void finalize() throws Throwable { }

对于C++程序员来说, 可能会把finalize()方法当作析构函数来释放资源. 但是在Java语言中通常是垃圾回收器来释放资源, 不需要程序员关心相关的操作.

总而言之, finalizers不会保证一定会立刻执行, 甚至不保证一定会执行. 所以finalize()中执行
的内容是完全不可靠的.

System.gc()和System.runFinalization()方法可以增加finalize()执行的概率, 但是也不能保证一定执行. System.runFinalizersOnExit(boolean value)和Runtime.runFinalizersOnExit(boolean value)方法可以保证finalize()执行, 但是它们存在安全问题, 可能导致线程死锁, 所以已经被废弃了.

finalizers会有严重的性能问题而且会忽略异常, 这也是不使用finalizers的重要理由.

对于需要关闭的资源, 比如文件, 我们可以通过提供一个close()方法, 让客户端手动调用关闭资源. 就像InputStream等IO接口的处理方式.

finalizers还是有一定用处的, 比如上述中对于文件等资源需要客户端手动调用关闭方法, 如果客户端没有触发则会导致文件资源没有关闭, 造成系统异常. 所以我们可以通过在finalizers中实现关闭逻辑, 提供一个兜底能力. 像FileInputStream等类都实现了这一功能.

还有一种场景是针对native对象的, 这里没有查到实际的使用场景, 为避免误导就不过多解释了.

当我们不得不使用finalizers时, 还需要注意一点, 子类执行finalize方法后不会自动触发执行父类的finalize方法, 所以需要手动触发. 为了防止子类没有执行父类的finalize方法, 作者提供了一种方法如下:

public class Foo{

    private final Object finalizerGuardian = new Object(){
        @Override
        protected void finalize() throws Throwable{
            do something;
        }
    };
}

有其他类Son继承Foo后, 并实现了finalize且没有触发父类的finalize方法, 当Son被回收时执行finalize方法, 此时不会执行Foo的finalize方法, 但是Foo唯一持有finalizerGuardian对象引用, Foo被回收finalizerGuardian也会被回收, 所以会执行finalizerGuardian的finalize方法, 所以通过这种方式就不会出现被子类覆盖不执行的情况.

总之日常工作开发不要使用finalizers, 如果要用到作为兜底逻辑, 那么记得使用finalizerGuardian方式防止被覆盖, 而且要打印必要的日志.

END

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值