首页 > 解决方案 > 在java的exec上关闭流的正确方法是什么?

问题描述

Runtime.getRuntime().exec(command);

我看到正在发生的系统调用显示 2~3 个文件描述符(FIFO 管道)。使用 try-with-resource 模式关闭它们的正确方法是什么?

在 java 论坛上发现的大多数历史部落知识表明:

# out of date!
... } finally {
            IOUtils.closeQuietly(p.getOutputStream());
            IOUtils.closeQuietly(p.getInputStream());
            IOUtils.closeQuietly(p.getErrorStream());
}

但这听起来不对,因为 1) 方法closeQuietly已被弃用,并且大多数库建议使用 try-with-resource,2) 它不优雅,因为我可能不一定拥有所有流。简单地将 exec() 调用移到 try 中感觉不对,因为它不是我将调用 close() 的资源。

标签: javaexectry-with-resources

解决方案


没有必要关闭它们;当进程终止时,它们自己关闭。如果进程永远不会死,它也不是必需的:要么你经常创建一个新的永不消亡的进程,在这种情况下,无论你是否关闭它们,你的系统都会崩溃并耗尽资源,或者你只创建它一次,在这种情况下,这些资源不会很重要。值得一提的是,这些资源是相当轻量级的资源,而且通常它们根本无法“关闭”,因为资源可以“释放”——关闭它们要么使它们保持打开状态,但拒绝进一步聊天(并在需要的地方发送 EOF) ,或将它们重新路由到 /dev/null;通常进程在 em 上只有 3 个管道,并且会继续拥有它们,直到进程终止。

是的,closeQuietly 对于几乎所有目的来说都是一个愚蠢的想法,所以它就在这里。如果关闭这些流以某种方式失败,您可能不想默默地忽略它。

如果您必须关闭它们,则这 3 个中的各个流都是可关闭的。但是,请注意,您正在阅读经验法则并尝试将它们当作福音真理来应用。try-with-resources 并不总是正确的答案,try-with-resources 也不是 100% 总是替代 close,更不用说 closeQuietly。

例如,try-with-resources 是专门围绕一段使用时间设计的。您声明资源应该可用的语句范围(与try块一起使用的大括号),然后构造将确保仅在代码流转换出该语句范围时才关闭资源,无论它如何退出这个。这也使它在这里可能无关紧要!

  1. 您正在开始一个长期存在的过程,并且不关心输入/输出。您只希望进程运行并继续运行。这意味着根本没有跨度,close()如果您觉得尝试保存资源很重要,即使这很可能根本没有任何效果,您也应该调用这些。没有跨度的语句意味着 try-with-resources 是不正确的。

  2. 您正在开始一个与之交互的短暂过程。“关闭”的正确方法是流程本身,但您不能为此使用 try-with-resources。这只能用于自动关闭。(代表它们的类实现 AutoClosable 的资源。大多数会,有些不会。锁是一个著名的。进程是另一个:要“关闭”它,你调用destroy()甚至destroyForcibly(). 你不能使用 try-with-resources (不是没有破坏目的的丑陋黑客)来做到这一点!一旦你关闭/破坏了这个过程,随之而来的流也死了。

  3. 更一般的原则是:如果你创建它,你就关闭它。如果你从不打电话getOutputStream(),你就永远不会创建它们。在某些操作系统上,获取这些流然后关闭它们比不这样做浪费更多的资源。因此,如果参数基于某种纯度模型,那么您也不应该关闭它们。如果它基于语用学,您必须测试这些资源的实际重量(很可能,非常轻),关闭它们是否真的为您节省了一些管道(很可能,它不会),以及close()-ing 的结果是否如果上述问题的答案具有相关性,则调用getOutputStream()该过程甚至会有所帮助(它可能会,但规范不保证这一点)。


推荐阅读