Owen
Owen

Reputation: 39366

Can other methods be called after finalize()?

If I have

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;
    }
}

Is it guaranteed, even in the face of multiple threads, assuming only the GC will call finalize(), that the IllegalStateException will never be thrown?

I know that in the face of a finalize() method that causes the object to be not garbage-collectable, the object won't be garbage collected and other methods might be called. But this finalize() doesn't do that. Is there still a possibility of foo() being called after finalize()?

Upvotes: 4

Views: 206

Answers (2)

Michael Markidis
Michael Markidis

Reputation: 4191

As Jon Skeet mentioned, it's entirely possible for methods to get called while one thread is currently in your finalization process.

To guard against this, you can certainly make the code thread-safe.

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;
        }
    }
}

Note: To be extra cautious, I would put the call to super.finalize() in a try/finally block:

@Override public void finalize() {

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

Upvotes: 0

Jon Skeet
Jon Skeet

Reputation: 1504162

It's entirely possible that a different object which had a reference to the instance of Foo is being finalized at the same time - and may resurrect the Foo object, allowing it to be used after finalization. This is kinda rude, but can certainly happen.

Even without resurrection, another finalizer could call Foo.foo() from its finalizer:

public class Bar {
    private final Foo foo;

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

Upvotes: 7

Related Questions