是否需要手动销毁并关闭java.lang.Process的开放流?

Is it required to manually destroy and close the open streams of a java.lang.Process?

我有以下代码:

Process proc;
try
{
    ProcessBuilder procBuilder = new ProcessBuilder(/* some args */);
    proc = procBuilder.start();
    if (proc.waitFor(30000, TimeUnit.MILLISECONDS))
    {
        //Etc...
    }
    else
    {
        //Handle it
    }
}
catch (InterruptedException ie)
{
    currentThread().interrupt();
}
finally
{
    //What goes here?
}

我试图找到一些来源表明是否需要调用 proc.destroy()(我应该在调用 destroy 之前检查 isAlive() 吗?),并手动关闭它的 input/output/error流,无济于事。据我所知,甚至官方文档也没有明确说明这一点。

当我完成生成的进程时执行这些操作是否有必要,甚至只是一种好的做法?

最好在 finally 块中调用 process.destroyForcibly()waitFor 如果进程没有在超时前完成,则不会终止该进程,因此在生成的进程无限期挂起的情况下,如果您不终止它,它可能会永远存在。

另一个用例是假设您的进程需要大约 25 秒才能正常终止。假设您的线程在启动后几乎立即被中断。最好终止进程而不是一直保留它 运行,因为无论如何都不会使用结果。

关于流,请参阅 Properly closing Java Process InputStream from getInputStream

虽然 正确地解决了答案的“销毁”部分,并且我回应了建议使用 finally 块的建议,但原始问题还询问了有关关闭流的问题,并且有一个微妙的问题差异。

在 Linux、macOS 和 BSD Unix 平台上,destroy() 实现会自动关闭流,因此对于这些平台来说,只需销毁进程并获得流关闭就足够了.

但是,在 Windows 和 Solaris (SunOS) 平台上,本机 destroy() 实现仅执行 TerminateProcesskill 并且不会关闭流。 JDK8 source code.

中甚至还有一个 StreamsSurviveDestroy 测试用例(仅限 Solaris)

因此,如果您在代码中支持 Windows 或 Solaris,除了添加 destroy()destroyForcibly() 之外,您还应该尝试关闭输入、输出和错误流在 finally 块中调用。此流关闭可以在销毁调用之前或之后完成。