为什么在Java中不使用finalize()方法

来源:互联网 发布:长歌门捏脸数据 编辑:程序博客网 时间:2024/04/30 20:49

我们都知道finalize()方法是回收分配给对象的内存之前调用垃圾收集器线程的基本语句。在这篇文章中,我们将会深入这个方法。

这篇文章中的章节:

1、finalize()方法不能保证执行(这个将要用例子来说明)

2、其他不使用它的原因

3、finalize()方法在性能上增加负担

4、正确使用的指导

finalize()方法不能保证执行(这个将要用例子来说明)

让我们使用一个程序证明它,我已经写了一个简单的Java runnable例子,在try-catch-finally-finalize块中每个里边都有输出语句。我已经创建了另一个类,并创建runnable的三个实例,然后我们看一下执行的过程。
public class TryCatchFinallyTest implements Runnable {     private void testMethod() throws InterruptedException    {        try        {            System.out.println("In try block");            throw new NullPointerException();        }        catch(NullPointerException npe)        {            System.out.println("In catch block");        }        finally        {            System.out.println("In finally block");        }    }     @Override    protected void finalize() throws Throwable {        System.out.println("In finalize block");        super.finalize();    }     @Override    public void run() {        try {            testMethod();        } catch (InterruptedException e) {            e.printStackTrace();        }    }}

public class TestMain{    @SuppressWarnings("deprecation")    public static void main(String[] args) {    for(int i=1;i<=3;i++)    {        new Thread(new TryCatchFinallyTest()).start();    }    }} Output: In try blockIn catch blockIn finally blockIn try blockIn catch blockIn finally blockIn try blockIn catch blockIn finally block

很神奇,线程中的finalize方法一点也没有执行,这已经证明了我刚刚说明的事情。我想发生这件事的原因是:finalizer是由垃圾收集器中的独立线程控制执行的,如果Java虚拟机存在太久,垃圾回收器没有时间创建和执行finalizers,如果错了,请说明。
下一个问题是,我们能够强制它执行吗
答案是:是的,可以,使用Runtime.runFinalizersOnExit(true);方法
public class TestMain{    @SuppressWarnings("deprecation")    public static void main(String[] args) {        for(int i=1;i<=3;i++)        {            new Thread(new TryCatchFinallyTest()).start();            Runtime.runFinalizersOnExit(true);        }    }} Output: In try blockIn catch blockIn finally blockIn try blockIn try blockIn catch blockIn finally blockIn catch blockIn finally blockIn finalize blockIn finalize blockIn finalize block

还有另一个方法,Runtime.getRuntime().runFinalization(); 但是这只能保证GC做出最大的努力,即使在我们的程序中,我们也不能保证3个线程中的finalize方法都能执行。
前一步,我们使用Runtime.runFinalizersOnExit(true); 方法,这是另一个遗憾,这个方法已经被JDK弃用,原因是:这种方法本质上是不安全的,可能导致finalizers方法被活对象调用而其他线程正在并行操作这个对象,从而导致不正确的行为或者死锁。所以,我们不能以一种方式执行它而以另一种方式置系统于危险中,最好我们不使用它。

其他不使用它的原因

(1)finalize()方法不像构造方法在链中工作,意味着像当你调用构造方法的时候,超类中的构造方法也会被隐含的调用,但是在finalize()方法的这种情况中,这种隐含的调用不会发生。超类中的finalize()方法需要显示的调用。
假设,你创建了一个类并且小心翼翼的写了finalize()方法。一些人来extend了你的类,但是在子类中的finalize()块中没有调用super.finalize()方法。然后超类中finalize()方法将永远都不会被调用。
(2)任何有finalize()方法抛出的异常都会被GC线程忽略而且不会被进一步传播,事实上也不会在日志文件上记录下来。

finalize()方法在性能上增加负担

在第二版的effective Java中,作者说:“这有另外一件事,使用finalize()方法还有另外的严重的性能问题,在我的机器上,创建和销毁一个简单的对象的时间大概是5.6ns,增加finalize()方法这个时间增加到2400ns,换句话说,使用finalize()方法创建和销毁对象比不使用慢了430倍”。我也在我的系统上分析上述问题,但是没有这么大的差别,但是也是有一些差别的。但是在时间要求高的系统内,这也是一个很大的区别。

正确使用的指导

经过上边的讨论之路,如果你依旧发现在一些场景下使用finalize()方法是别要的,那么请检查下边的观点
(1)要在finalize()方法中一直调用super.finalize()
(2)考虑到不可预测预测性,不要在时间要求高的应用中使用finalize()
(3)不要使用Runtime.runFinalizersOnExit(true);方法,因为你可能将你的系统置于危险之中
(4)尝试遵循下边的模板使用finalize()方法
@Overrideprotected void finalize() throws Throwable{    try{        //release resources here    }catch(Throwable t){        throw t;    }finally{        super.finalize();    }}

原文链接:http://howtodoinjava.com/2012/10/31/why-not-to-use-finalize-method-in-java/
0 0
原创粉丝点击