是否需要手动销毁和关闭 java.lang.Process 的打开流?
Posted
技术标签:
【中文标题】是否需要手动销毁和关闭 java.lang.Process 的打开流?【英文标题】:Is it required to manually destroy and close the open streams of a java.lang.Process? 【发布时间】:2020-10-20 03:37:21 【问题描述】:我有以下代码:
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()
吗?),并手动关闭其输入/输出/错误流,但无济于事。据我所知,即使是官方文档也没有说明这一点。
当我完成生成的进程后执行这些操作是否有必要,甚至只是一种良好的做法?
【问题讨论】:
您当然应该关闭进程的输出流。否则它可能会阻止在其stdin
上等待流结束。
如果进程产生输出,你需要对它做一些事情。如果您不关心输出,请使用procBuilder.inheritIO();
(在启动进程之前)使其与您的 Java 程序的输出出现在同一位置。
【参考方案1】:
在 finally 块中调用 process.destroyForcibly()
是个好主意。 waitFor
不会杀死进程,如果它没有在超时之前完成,所以在生成的进程无限期挂起的情况下,如果你不杀死它,它可能会永远存在。
另一个用例是假设您的进程需要大约 25 秒才能正常终止。假设您的线程在启动后几乎立即被中断。最好终止进程而不是让它一直运行,因为无论如何都不会使用结果。
关于流,见Properly closing Java Process InputStream from getInputStream
【讨论】:
【参考方案2】:虽然Michael's answer 正确解决了答案的“破坏”部分,并且我回应了按照建议使用finally
块的建议,但最初的问题还询问了关于关闭流的问题,并且存在细微差别。
在 Linux、macOS 和 BSD Unix 平台上,destroy()
实现会自动关闭流,因此对于这些平台,只需销毁进程并获得流关闭就足够了。
但是,在 Windows 和 Solaris (SunOS) 平台上,本机 destroy()
实现仅执行 TerminateProcess
或 kill
并且不会关闭流。 JDK8 source code 中甚至还有一个 StreamsSurviveDestroy
测试用例(仅限 Solaris)。
因此,如果您在代码中支持 Windows 或 Solaris,则除了在 finally
块中添加 destroy()
或 destroyForcibly()
调用外,还应尝试关闭输入、输出和错误流。这个流闭包可以在destroy调用之前或之后完成。
【讨论】:
以上是关于是否需要手动销毁和关闭 java.lang.Process 的打开流?的主要内容,如果未能解决你的问题,请参考以下文章