简体   繁体   English

在 Java 中替换 finalize()

[英]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. Object.finalize()在 Java 9 中已被弃用,我想我明白原因,但我无法看到如何替换它。

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.我有一个名为 Configuration 的实用程序类,它本质上有一个实例,该实例拥有应用程序中的所有内容,并在应用程序的整个过程中持续存在。 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).它提供的服务之一是日志记录:在第一次请求记录消息时,会创建一个记录器(出于各种遗留原因,它是我自己的记录器而不是标准记录器),并在 Configuration 对象的字段中保存一个引用,并且在应用程序终止时,无论是正常还是异常,我想释放记录器持有的任何资源(这是一个黑匣子,因为我的库的用户可以提供他们自己的实现)。

Currently this is achieved with a Configuration.finalize() method that calls logger.close() .目前这是通过调用logger.close()Configuration.finalize()方法实现的。

What should I be doing instead?我应该怎么做?

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. Java 9 引入了Cleaner和 Cleanable 实用程序类,它们负责将幻像引用连接到队列和清除该队列的清理线程。

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, ie it is still preferable to rely on AutoClosable and try-with-resources blocks to manage the lifecycle of resources, not on the garbage collector.虽然这可以让您分离出将在拥有对象死亡后执行事后清理的见证人,但关于 GC 触发的资源管理的所有警告仍然适用,即仍然最好依赖AutoClosable和 try-with-resources块来管理资源的生命周期,而不是垃圾收集器。

Phantom references are general replacement for finalize() . 幻像引用finalize()一般替代。 Many classes from Java runtime are already using them. Java 运行时的许多类已经在使用它们。

Using Phantom references is a bit laborious, you have to maintain own reference list and postmortem processing thread.使用Phantom 引用有点费力,你必须维护自己的引用列表和事后处理线程。 On the other hand you are fully in control.另一方面,您完全可以控制。

Here is a simple example of Phantom reference setup.这是Phantom 参考设置的简单示例

This article explains and compares implementation of Java finalize() and Phantom references . 本文解释并比较了 Java finalize()Phantom 引用的实现

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这在 VM 终止时被调用,因此在您的特定情况下它应该是finalize一个很好的替代品

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.记录器本身可以而且应该这样做(与 IO 流或数据库连接不同),它应该存在很长时间。

But you already provide logger.close() ... OK, then I'd suggest the following:但是您已经提供了logger.close() ... 好的,那么我建议如下:

  • Ensure that close is idempotent, ie, closing the logger the second time is a no-op.确保close是幂等的,即第二次关闭记录器是无操作的。
  • 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.使用Runtime#addShutdownHookPhantomReference ,并让它们都调用logger.close() ,以便在 JVM 终止或您的应用程序被logger.close()同时调用它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM