我们最近将我们的消息处理应用程序从Java 7升级到Java 8.自升级以来,我们偶尔会遇到一个流在读取时被关闭的异常.记录显示终结器线程正在调用finalize()保存流的对象(进而关闭流).
代码的基本概要如下:
MIMEWriter writer = new MIMEWriter( out );
in = new InflaterInputStream( databaseBlobInputStream );
MIMEBodyPart attachmentPart = new MIMEBodyPart( in );
writer.writePart( attachmentPart );
Run Code Online (Sandbox Code Playgroud)
MIMEWriter并且MIMEBodyPart是本土MIME/HTTP库的一部分. MIMEBodyPart扩展HTTPMessage,具有以下内容:
public void close() throws IOException
{
if ( m_stream != null )
{
m_stream.close();
}
}
protected void finalize()
{
try
{
close();
}
catch ( final Exception ignored ) { }
}
Run Code Online (Sandbox Code Playgroud)
异常发生在调用链中MIMEWriter.writePart,如下所示:
MIMEWriter.writePart() 写入部件的标题,然后调用 part.writeBodyPartContent( this )MIMEBodyPart.writeBodyPartContent()调用我们的实用工具方法 …我正在尝试用Java编写DagNode类,其中两个节点在逻辑上是相等的,如果它们等于作为引用.
C++中的想法 - (我来自C++) - 将使用智能指针和引用计数:
创建节点时,如果该节点已存在,我将在某个表中查找.如果是这样,我会返回指向旧指针的指针.否则,请创建一个新节点.
重载构造函数和析构函数等重载的C++方法将执行引用计数,当节点的引用计数降为0时,该节点将从上述表中逐出.(C++也将释放内存.)
但是,似乎没有办法在Java中自动进行ref-counting.我需要做裁判计数知道何时驱逐从表中的一个节点(以便它可以被垃圾收集),我真的想避免调用node->incRef(),并node->decRef()在每个函数的开始和结束.
我们如何在Java中使用这个C++习语?
(此问题不同于您为什么要实现finalize()?此问题与从Java平台弃用有关,另一个问题与在应用程序中是否应使用此机制有关。)
为什么finalize()在Java 9中不推荐使用该方法?
是的,它可能以错误的方式使用(例如,从垃圾收集中保存对象(尽管仅一次)或尝试关闭其中的某些本机资源(比完全不关闭更好))以及许多其他方法可能会被错误地使用。
那么,finalize()真的有这么危险的或绝对无用,它是必要踢出来的Java?
我正在使用 Mysql GET_LOCK在分布式系统中实现锁定服务。在调用我的 getLock() 方法时,如果客户端获得了锁,我会在数据库中创建一个条目并在释放锁时删除该条目。
假设调用客户端将在达到其目的后释放锁。但是,我想确保在客户端不释放它或不进行适当清理的情况下释放锁。
一种方法是在我的锁定对象上使用 finalize 方法以在调用 finalize 时释放它。然而,它并不理想,增加了复杂性并且在 Java 9 中被弃用。我读到了比终结器更好的 Phantom 引用,但它的复杂程度也很高。我把它作为我的最后手段。
有没有更简单、更少依赖 JVM 的方法来处理这个用例?
java garbage-collection phantom-reference finalize finalizer