如果流没有手动关闭,什么时候关闭?

When does a stream close if its not closed manually?

我想知道如果流没有手动关闭,它什么时候关闭。我的意思是,如果流的引用范围不再存在,流是否会被关闭?

考虑以下示例场景。

Class A{
 InputStream in;
 OutputStream out;
 A(){
  // Initialize and create the streams.
 }
 ...
}
Class B{
 public void myMethod(){
 A a = new A();
 System.out.println("End of my method.")
 }
...
}

在这里,一旦我完成了流,我将退出 myMethod() 但是依次处理的程序不会终止并继续进行其他操作。

我没有关闭流。 classA的引用范围结束后会自动关闭吗? (即 myMethod() 何时结束)? GC 会处理这个吗?另外,我读到一旦进程结束,流就会关闭,系统会释放为它保留的所有资源,供其他进程使用。我们如何检查流是否打开? Java 中有任何 linux 命令或选项可以检查吗?

感谢任何帮助!

我认为 JVM 规范对此没有任何保证。您确实应该 finally 关闭这些资源。

当进程结束时,操作系统将释放与其关联的所有资源(包括内存、文件句柄和网络套接字)。

有 OS 工具可以检查打开的文件和流,例如 lsof

这是一种糟糕的编程习惯,是程序员的错误。根据底层数据源的不同,它可能永远不会关闭并且可能会发生泄漏。您必须在完成任何资源后关闭它,在 finally 块中,或者在 Java 7 或更高时使用资源尝试,以确保即使抛出异常也能关闭它。

InputStream in;
OutputStream out;
try {
   // Do your stuff with the streams
} finally {
   if (in != null) {
       in.close();
   }
   if (out != null) {
       out.close();
   }
}

如果您不手动关闭它,那么所有非托管资源都将在进程终止时释放,但这不是推荐或最佳做法。完成后,您应该始终关闭流。

管理流的更好的建议方法是使用 try with resource 选项,如下所示:

try (InputStream input = new FileInputStream(...);
     Reader reader = new InputStreamReader(input, ...)) {
   ...
}

I did not close the streams. Will it be closed automatically once the scope of the reference to class A ends?

不,它不会自动关闭。

一个很好的参考是:

Better Resource Management with Java SE 7: Beyond Syntactic Sugar

FileInputStream 的情况下,有一个 finalize() 方法可以在流被垃圾收集时释放资源。

并不是说您可以或应该依赖它。 FileInputStream 就是这样做的。另一方面,SocketInputStream 覆盖 finalize() 以显式不执行任何操作,依靠 Socket 关闭资源(并且 Socket 没有 finalize() 方法) .

使用Java7,可以在try语句中创建一个或多个“资源”。 “资源”是实现 java.lang.AutoCloseable 接口的东西。此资源将自动关闭并结束 try 块。

您可以查看 this and java doc 了解更多信息

private static void printFileJava7() throws IOException {

    try(FileInputStream input = new FileInputStream("file.txt")) {

        int data = input.read();
        while(data != -1){
            System.out.print((char) data);
            data = input.read();
        }
    }
}

当 try 块完成时,FileInputStream 将自动关闭。这是可能的,因为 FileInputStream 实现了 Java 接口 java.lang.AutoCloseable。所有实现此接口的 类 都可以在 try-with-resources 结构中使用。

不保证只要 JVM 是 运行,资源就会被关闭,您建议的实现非常危险。

我会建议什么。 将 class A 设为 Closeable 并使用 Java 的 tryResourceClose-Statement。 这个例子在这里。 https://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html

离开 try 块后,您将有机会关闭您的资源。

流本身通常不知道它是否打开。 但是,您自己的 class A 可以跟踪流是否关闭。