其他方法能在finalize()之后调用吗?

4
如果我拥有
public class Foo {
    private boolean finalized = false;

    public void foo() {
        if (finalized)
            throw new IllegalStateException("finalize() has been called.");
    }

    @Override public void finalize() {
        super.finalize();
        finalized = true;
    }
}

即使在面对多个线程的情况下,只有GC会调用 finalize(),那么 IllegalStateException 是否一定不会被抛出呢?
我知道当 finalize() 方法导致对象不能被垃圾回收时,对象就不会被垃圾回收,其他方法可能会被调用。但是这个 finalize() 并没有做到那样的事情。即使在 finalize() 之后还会调用 foo() 的可能性吗?

1
你是不是想问,“在GC调用finalize之后?”否则,有些白痴可能会明确地对你调用它。 - bmargulies
@bmargulies 谢谢,那正是我想表达的意思。 - Owen
你应该将此方法保护起来,就像在对象中最初定义的那样,而不是将其公开以限制风险。 - Nicolas Filotto
2个回答

7
很有可能一个不同的对象持有了对于 Foo 实例的引用,并且在同一时间也正在进行终结。这个对象可能会使 Foo 对象复活,从而导致其在终结之后被使用。虽然这样做是有些不礼貌的,但确实可能发生。
即使没有复活,另一个终结器仍然可以从它的终结器中调用 Foo.foo() 方法。
public class Bar {
    private final Foo foo;

    @Override protected void finalize() {
        // The finalizer in foo may already have executed...
        foo.foo();
    }
}

0
正如Jon Skeet所提到的,当一个线程正在进行您的终结过程时,完全有可能调用方法。
为了防范这种情况,您可以确保代码是线程安全的。
public class Foo {
    private boolean finalized = false;

    public void foo() {
        synchronized (this)
        {
            if (finalized)
                throw new IllegalStateException("finalize() has been called.");
        }
    }

    @Override public void finalize() {

        synchronized (this)
        {
            super.finalize();
            finalized = true;
        }
    }
}

注意:为了更加谨慎,我会将调用super.finalize()的语句放在try/finally块中:

@Override public void finalize() {

        synchronized (this)
        {
            try
            {
                super.finalize();
            }
            finally
            {
                finalized = true;
            }
        }
    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接