Java 中 Process.destroy() 之后 stderr/stdout 流会发生什么?
我希望从 Java 启动的进程有一个超时。超时后,我想终止该进程。到目前为止,一切都很好。问题是,我想在正常执行期间和超时后捕获 stderr/stdout 。如果我用 destroy() 终止进程会发生什么?我可以检索到目前为止生成的(部分)stderr/stdout 吗?还是他们走了?
I'd like to have a timeout for a process I start from Java. After the timeout, I'd like to kill the process. So far, so good. Problem is, I want to capture stderr/stdout during both normal execution and after a timeout. What happens if I kill the process with destroy()? Can I retrieve the (partial) stderr/stdout produced so far? Or are they gone?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
进程处理本质上是特定于操作系统的,我在这里专门研究 Java 如何处理 Unix 进程。
不幸的是
Process
在调用.destroy()
。我不知道为什么 JDK 设计者认为这是正确的设计模式,但它确实使处理终止的进程变得更加复杂。值得注意的是,
InputStream
的Process
保存的是ProcessPipeInputStream
实际上有一个drainInputStream( )
方法完全符合我们的要求 - 它读取支持文件描述符中的任何剩余字节并将它们存储在我们的字节缓冲区中。该方法“在进程退出时由进程收割者线程调用”,但不幸的是,当进程被.destroy()
执行TERM
时,该方法不会被调用。那么你能期望的最好的结果就是临时操纵你自己的
drainInputStream()
行为,并在调用之前为stdout
和stderr
调用它.destroy()
。在耗尽数据之后、.destroy()
完成之前,仍有可能将某些数据写入任一流,但这将获取其中的大部分。Process handling is inherently OS-specific, I'm looking specifically at how Java handles Unix processes here.
It's unfortunate that
Process
closes its streams when you call.destroy()
. I don't know why the JDK designers felt that was the right design pattern, but it certainly makes dealing with terminated processes more complicated.It's worth noting that the
InputStream
sProcess
holds are instances ofProcessPipeInputStream
which actually has adrainInputStream()
method that does exactly what we'd want - it reads in any remaining bytes in the backing file descriptor and stores them in a byte buffer for us. This method is "called by the process reaper thread when the process exits", but unfortunately is not called when the process isTERM
'ed by.destroy()
.The best you can hope for then is to jury-rig your own
drainInputStream()
behavior and call that for bothstdout
andstderr
before you call.destroy()
. It's still possible for some data to being written to either stream after you drain them but before.destroy()
finishes, but this will get most of it.除了调用 Process.exec()/waitFor 的线程之外,您应该有一个或两个单独的线程读取 stdout 和 stderr(如果合并它们,则一个) ()/destroy()。读取线程将获取 EOF 之前生成的任何数据。如果您调用 Process.destroy(),EOF 可能会更快发生,仅此而已。
You should have one or two separate threads reading
stdout
andstderr
(one if you merge them), apart from the thread that callsProcess.exec()/waitFor()/destroy()
. The reading thread(s) will get any data that is produced up to an EOF. If you callProcess.destroy()
, the EOF may happen sooner, that's all.对于任何未来的时间旅行者 -
Process.destroy()
确实会关闭流,正如 @dimo414 的答案指出的那样。然而,进程的实际终止是由Process.toHandle()
检索的ProcessHandle
来处理的,这就是Process.destroy()
之前所做的事情然后它继续并关闭流。因此,长话短说,可以通过执行以下操作来终止进程而不关闭流:
For any future time-travellers -
Process.destroy()
indeed closes the streams as @dimo414's answer points out. However the actual termination of the process is handled by itsProcessHandle
retrieved byProcess.toHandle()
which is whatProcess.destroy()
does before it then goes ahead and closes the streams.So to cut a long story short, it is possible to terminate a
Process
without closing the streams by doing: