Java 垃圾收集中的可关闭?

Java 垃圾收集中的可关闭?,java,garbage-collection,Java,Garbage Collection,当垃圾收集Closeable对象时,是否调用Closeable接口的close()方法?[在java 6.0中] 我有一个静态变量,它是一个资源(数据库连接)。由于这是一个静态资源,因此没有正确的位置来显式调用close()。也许您可以使用?如果不关闭连接,将导致连接内存泄漏;除非应用程序服务器/web服务器关闭。 您可以通过调用自定义关闭方法或使用finalize关闭所有连接 public void closeConnection { try { rs.close(); } c

当垃圾收集
Closeable
对象时,是否调用
Closeable
接口的
close()
方法?[在java 6.0中]


我有一个静态变量,它是一个资源(数据库连接)。由于这是一个静态资源,因此没有正确的位置来显式调用
close()

也许您可以使用?

如果不关闭连接,将导致连接内存泄漏;除非应用程序服务器/web服务器关闭。 您可以通过调用自定义关闭方法或使用finalize关闭所有连接

public void closeConnection {
        try { rs.close(); } catch (Exception e) { // TODO Auto-generated catch block }
        try { ps.close(); } catch (Exception e) { // TODO Auto-generated catch block }
        try { conn.close(); } catch (Exception e) { // TODO Auto-generated catch block }
    }


它取决于“Closeable”接口的实现,以及它希望如何处理垃圾收集。例如,实现对象#finalize()方法,以调用Closeable#close()方法

快速回答:不。GC根本不关心
Closeable

Java确实有
protectedvoidfinalize()抛出可丢弃的{}
方法,您可以重写该方法,它将在GC上调用。它在某种程度上起作用,例如在
FileInputStream
中:

/**
 * Ensures that the <code>close</code> method of this file input stream is
 * called when there are no more references to it.
 *
 * @exception  IOException  if an I/O error occurs.
 * @see        java.io.FileInputStream#close()
 */
protected void finalize() throws IOException {
    if ((fd != null) &&  (fd != FileDescriptor.in)) {

        /*
         * Finalizer should not release the FileDescriptor if another
         * stream is still using it. If the user directly invokes
         * close() then the FileDescriptor is also released.
         */
        runningFinalize.set(Boolean.TRUE);
        try {
            close();
        } finally {
            runningFinalize.set(Boolean.FALSE);
        }
    }
}
问题是,它产生的问题超过了它的价值:例如,JVM不保证它会调用这个方法。也就是说,您不应该将其用于资源处理;您在上面看到的是一个安全网,可以减少文件处理程序泄漏的危害

还有一个问题是,-也就是说,只要你的类是可见的。所以你没有机会使用定稿

不过,您可以做的是使用——它将为您的应用程序添加另一层安全网,让您有机会在退出时优雅地关闭连接。考虑到您使用的是静态字段,无论如何,您的连接的寿命可能与JVM的相同


不过,我建议您检查一下这种方法。

您确定连接需要是静态的吗?Public或private,将连接声明为static不会在较小的应用程序中添加任何内容,而在较大的应用程序中会增加不必要的复杂性;基本上,您需要确保该连接的每个访问都是线程安全的。共享一个连接听起来是个好主意,不必每次都声明、设置和打开一个连接,但这并不是慢的部分。同意。至少将连接放在一个单例中,可能会给您在将来添加时提供更好的机会。在此上下文中,单例与静态字段没有什么不同。毕竟,它是一个静态字段。@user949300事实上,我已经将它实现为一个单例类。。在这个资源上下文中没有任何区别。因为,它只是一个连接,任何数量的客户端都可以并行访问它。我认为不需要任何锁机制来确保在任何时间点只有一个客户机“持有”资源。如果我错了,请纠正我。@raj据我所知,数据库连接不是隐式设计来处理并发性的,因此有很多关于各种问题的讨论;执行新语句时,
ResultSet
关闭,可能是其中之一。即使是线程安全的,单个连接一次也只能执行一条语句,因此任何时候一次执行多个线程,都有人在等待。因此,在连接池上使用共享连接的好处仍然很少。以单例模式设置连接池,并从中获取唯一的连接。问题是,静态引用将使对象不符合收集条件,因为它是可访问的,因此不是垃圾。因此,
finalize
根本不会被调用。我还要声明您提供的链接不正确/过时。它声明“通常应该重写It(finalize)以清理非Java资源”。当前的最佳做法是永远不要覆盖finalize()。永远不要忽略异常。在这里忽略
SQLException
是很正常的,并且与预期的一样;忽视NPE已经是一种不好的做法,因为它可以明确地做到;忽略任何其他异常都意味着您错过了可能的错误。忽略finally子句中的异常是常见的,可以说是良好的做法。您可以捕获或忽略它//待办事项
/**
 * Ensures that the <code>close</code> method of this file input stream is
 * called when there are no more references to it.
 *
 * @exception  IOException  if an I/O error occurs.
 * @see        java.io.FileInputStream#close()
 */
protected void finalize() throws IOException {
    if ((fd != null) &&  (fd != FileDescriptor.in)) {

        /*
         * Finalizer should not release the FileDescriptor if another
         * stream is still using it. If the user directly invokes
         * close() then the FileDescriptor is also released.
         */
        runningFinalize.set(Boolean.TRUE);
        try {
            close();
        } finally {
            runningFinalize.set(Boolean.FALSE);
        }
    }
}