问题描述
我想在java代码中调用外部程序,然后Google告诉我Runtime或ProcessBuilder可以帮助我完成这项工作。我已经尝试过了,并且出现了java程序无法退出的问题,这意味着子进程和父进程都会永远等待。他们是悬挂或死锁。
I want to invoke an external program in java code, then the Google tell me that the Runtime or ProcessBuilder can help me to do this work. I have tried it, and there come out a problem the java program can't exit, that means both the sub process and the father process wait for forever. they are hanging or deadlock.
有人告诉我原因是子进程的缓存太小了。当它试图将数据返回给父进程,但是父进程没有及时读取它时,它们都挂起了。所以他们建议我分叉一个线程来负责读取子进程的缓存数据。我这样做就像他们告诉我的那样,但仍有一些问题。
Someone tell me the reason is that the sub process's cache is too small. when it try to give back data to the father process, but the father process don't read it in time, then both of them hang. So they advice me fork an thread to be in charge of read sub process's cache data. I do it as what they tell me, but there still some problem.
然后我关闭getOutputStream()方法得到的输出流。最后,该计划取得了成功。但我不知道为什么会这样?输出流和输入流之间是否存在某种关系?
Then I close the output stream which get by the method getOutputStream(). Finally, the program success. But I don't know why it happen? Is there some relationship between the output steam and input stream?
推荐答案
您在问题中提供的细节很少,所以我可以只提供一般答案。
You have provided very few details in your question, so I can only provide a general answer.
所有流程都有三个标准流:标准输入,标准输出和标准错误。标准输入用于读取数据,标准输出用于写出数据,标准错误用于写出错误消息。当您使用 Runtime.getRuntime()。exec()
或 ProcessBuilder
启动外部程序时,Java将创建一个处理外部程序的
对象,这个 Process
对象将有方法来访问这些流。
All processes have three standard streams: standard input, standard output and standard error. Standard input is used for reading in data, standard output for writing out data, and standard error for writing out error messages. When you start an external program using Runtime.getRuntime().exec()
or ProcessBuilder
, Java will create a Process
object for the external program, and this Process
object will have methods to access these streams.
这些流的访问方式如下:
These streams are accessed as follows:
-
process.getOutputStream()
:返回外部程序的标准输入。这是一个OutputStream
,因为它是您的Java代码将写入的内容。 -
process.getInputStream()
:返回外部程序的标准输出。这是一个InputStream
,因为它是您的Java代码可以读取的内容。 -
process.getErrorStream()
:返回外部程序的标准错误。这是一个InputStream
,就像标准输出一样,它是你的Java代码可以读取的东西。
process.getOutputStream()
: return the standard input of the external program. This is anOutputStream
as it is something your Java code will write to.process.getInputStream()
: return the standard output of the external program. This is anInputStream
as it is something your Java code will read from.process.getErrorStream()
: return the standard error of the external program. This is anInputStream
as, like standard output, it is something your Java code will read from.
请注意, getInputStream()
和 getOutputStream()
的名称可能令人困惑。
Note that the names of getInputStream()
and getOutputStream()
can be confusing.
Java代码和外部程序之间的所有流都是缓冲的。这意味着每个流都有少量内存(缓冲区),其中编写器可以写入尚未被读取器读取的数据。作者不必等待读者立即读取其数据;它可以将其输出保留在缓冲区中并继续。
All streams between your Java code and the external program are buffered. This means each stream has a small amount of memory (a buffer) where the writer can write data that is yet to be read by the reader. The writer does not have to wait for the reader to read its data immediately; it can leave its output in the buffer and continue.
有两种方法可以写入缓冲区并从中读取缓冲区:
There are two ways in which writing to buffers and reading from them can hang:
- 当数据空间不足时,尝试将数据写入缓冲区,
- 尝试从空缓冲区读取数据。
在第一种情况下,编写器将通过从中读取数据来等待缓冲区中的空间。在第二个,读者将等待数据写入缓冲区。
In the first situation, the writer will wait until space is made in the buffer by reading data out of it. In the second, the reader will wait until data is written into the buffer.
你提到关闭 getOutputStream()返回的流
导致您的程序成功完成。这将关闭外部程序的标准输入,告诉它没有更多内容可供阅读。如果你的程序成功完成,这表明你的程序正在等待它挂起时有更多的输入。
You mention that closing the stream returned by getOutputStream()
caused your program to complete successfully. This closes the standard input of the external program, telling it that there will be nothing more for it to read. If your program then completes successfully, this suggests that your program was waiting for more input to come when it was hanging.
如果你运行外部程序可能是有争议的程序,如果你不需要使用它,你应该关闭它的标准输入,就像你所做的那样。这告诉外部程序将不再有输入,因此消除了它等待输入的可能性。但是,它没有回答你的外部程序为什么等待输入的问题。
It is perhaps arguable that if you do run an external program, you should close its standard input if you don't need to use it, as you have done. This tells the external program that there will be no more input, and so removes the possibility of it being stuck waiting for input. However, it doesn't answer the question of why your external program is waiting for input.
大部分时间,当你使用 Runtime.getRuntime()。exec()或 ProcessBuilder
,您不经常使用标准输入。通常,您将命令行上所需的任何输入传递给外部程序,然后读取其输出(如果它生成任何输出)。
Most of the time, when you run external programs using Runtime.getRuntime().exec()
or ProcessBuilder
, you don't often use the standard input. Typically, you'd pass whatever inputs you'd need to the external program on the command line and then read its output (if it generates any at all).
你的外部程序做你需要它然后卡住,显然在等待输入?您是否需要将数据发送到标准输入?如果使用 cmd.exe / k ...
在Windows上启动进程,则命令解释程序将在其启动的程序退出后继续。在这种情况下,您应该使用 / c
而不是 / k
。
Does your external program do what you need it to and then get stuck, apparently waiting for input? Do you ever need to send it data to its standard input? If you start a process on Windows using cmd.exe /k ...
, the command interpreter will continue even after the program it started has exited. In this case, you should use /c
instead of /k
.
最后,我想强调一下有两个输出流,标准输出和标准错误。如果您在错误的时间从错误的流中读取,可能会出现问题。如果在缓冲区为空时尝试读取外部程序的标准输出,则Java代码将等待外部程序生成输出。但是,如果您的外部程序正在将大量数据写入其标准错误,它可能会填充缓冲区,然后发现自己正在等待Java代码通过读取它来在缓冲区中腾出空间。最终的结果是你的Java代码和外部程序都在等待彼此做某事,即死锁。
Finally, I'd like to emphasise that there are two output streams, standard output and standard error. There can be problems if you read from the wrong stream at the wrong time. If you attempt to read from the external program's standard output while its buffer is empty, your Java code will wait for the external program to generate output. However, if your external program is writing a lot of data to its standard error, it could fill the buffer and then find itself waiting for your Java code to make space in the buffer by reading from it. The end result of this is your Java code and the external program are both waiting for each other to do something, i.e. deadlock.
这个问题可以通过使用一个 ProcessBuilder
并确保使用 true redirectErrorStream()
方法$ c>价值。调用此方法会将外部程序的标准错误重定向到其标准输出,因此您只能读取一个流。
This problem can be eliminated simply by using a ProcessBuilder
and ensuring that you call its redirectErrorStream()
method with a true
value. Calling this method redirects the standard error of the external program into its standard output, so you only have one stream to read from.
这篇关于Java ProcessBuilder:输入/输出流的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!