Question

I want to check the condition in termination with finalize, but finalize never be executed each time. Can anybody tell me why?

public class Test
{

    public static void main(String[] args)
    {   
        Tank tank=new Tank();
        tank.fill();
        System.gc();
    } 
}  
public class Tank    {

    private boolean emptied=true;

    public void fill()
    {
        this.emptied=false;
    }

    public void empty()
    {
        this.emptied=true;
    }

    public Tank()
    {
        this.emptied=true;
    }

    protected void finalize()
    {
        if(this.emptied==false)
        {
            System.out.println("Termination Verification Error: Tank should be emptied");
        }
    }
}
Was it helpful?

Solution

The finalize() method is only called when the object is destroyed and finalized by the GC, which happens at some undefined point in time after the last reference to the object is discarded. If the object is never released (e.g. you still have a reference to it), then finalize() is never called.

Also bear in mind you have no control over when finalize() is called, or if it will ever even be called at all. See general description of Object.finalize().

Even System.gc() is not guaranteed to force the GC to do anything. It is only a suggestion to the JVM. See general description of System.gc()

In general, if you find yourself attempting to manipulate the GC like this in order to perform these types of checks, there are generally better ways. This is an inappropriate use of finalize() and the GC.

For example, if you're trying to check if a presumed condition is true, consider using assert in appropriate places (but be forewarned: assert is not a replacement for a functional if; it is merely to self-document and test conditions assumed at design time).

If part of your application's higher level functionality is to verify that a condition is true before exiting, then you should explicitly verify that the condition is true before exiting, e.g. in your case:

public static void main(String[] args)
{   
    Tank tank=new Tank();
    tank.fill();
    // check explicitly before terminating
    if (!tank.empty()) 
        System.err.println("Warning: Ending with non-empty tank!");
} 

An explicit check gives you full control over when it happens in addition to the ability to attempt a recovery from the error.

Update: Another good option, which MadProgrammer helpfully brought up in the comments below, is to use a shutdown hook, if that's appropriate for you. That will provide a clean way to exit code on shutdown if your application has multiple exit points that you can't otherwise eliminate or control.

For more complex applications, by the way, you will find testing strategies such as unit testing, etc., when combined with good modular design (e.g. clearly defined preconditions, postconditions, invariants), can provide complete tests of application logic without requiring self-testing to be part of the normal run of the application. Not that there's anything wrong with the latter, especially in simple applications, but it is something you may be interested in finding out about for future reference.

OTHER TIPS

As per JLS 12.6. Finalization of Class Instances

The Java programming language does not specify how soon a finalizer will be invoked, except to say that it will happen before the storage for the object is reused.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top