Michael Kay
Michael Kay

Reputation: 163282

Replacing finalize() in Java

Object.finalize() is deprecated in Java 9, and I think I understand the reasons why, but I'm having trouble seeing how to replace it.

I have a utility class called Configuration which essentially has a single instance that owns everything in the application and lasts for the duration of the application. One of the services it provides is logging: on first request to log a message, a logger is created (for various legacy reasons it's my own Logger rather than a standard one), with a reference held in a field of the Configuration object, and on application termination, whether normal or abnormal, I want to release any resources held by the logger (which is a black box since users of my library can supply their own implementation).

Currently this is achieved with a Configuration.finalize() method that calls logger.close().

What should I be doing instead?

Upvotes: 34

Views: 16676

Answers (4)

the8472
the8472

Reputation: 43042

Java 9 introduces the Cleaner and Cleanable utility classes which take care of wiring up phantom references to a queue and a cleaning thread draining that queue.

While this lets you separate out the witness that will perform a post-mortem cleanup after the owning object has died, all the caveats about GC-triggered resource management still apply, i.e. it is still preferable to rely on AutoClosable and try-with-resources blocks to manage the lifecycle of resources, not on the garbage collector.

Upvotes: 18

maaartinus
maaartinus

Reputation: 46382

IMHO it's not the responsibility of your application to tell the logger to clean up its own mess. The logger itself can and should do it as (unlike IO streams or DB connections), it's supposed to live long.

But you already provide logger.close()... OK, then I'd suggest the following:

  • Ensure that close is idempotent, i.e., closing the logger the second time is a no-op.
  • Use both Runtime#addShutdownHook and a PhantomReference, and let them both call logger.close(), so that it gets called both when the JVM terminates or your application gets GC'ed.

Upvotes: 2

Alexey Ragozin
Alexey Ragozin

Reputation: 8379

Phantom references are general replacement for finalize(). Many classes from Java runtime are already using them.

Using Phantom references is a bit laborious, you have to maintain own reference list and postmortem processing thread. On the other hand you are fully in control.

Here is a simple example of Phantom reference setup.

This article explains and compares implementation of Java finalize() and Phantom references.

Upvotes: 9

Lothar
Lothar

Reputation: 5449

You can add a Thread as shutdown hook to the Runtime:

Runtime.getRuntime().addShutdownHook(new Thread(() -> {
    // cleanup code
}));

This is called when the VM terminates, so it should be a good replacement for finalize in your particular case

Upvotes: 5

Related Questions