process.waitFor()永远不会返回

use*_*444 91 java runtime.exec

Process process = Runtime.getRuntime().exec("tasklist");
BufferedReader reader = 
    new BufferedReader(new InputStreamReader(process.getInputStream()));
process.waitFor();
Run Code Online (Sandbox Code Playgroud)

Joa*_*uer 138

有许多原因waitFor()无法归还.

但它通常归结为执行的命令不会退出的事实.

这也可能有很多原因.

一个常见原因是该过程产生一些输出,而您不从相应的流中读取.这意味着一旦缓冲区已满,该进程就会被阻止,并等待您的进程继续读取.你的进程反过来等待另一个进程完成(它不会因为它等待你的进程,...).这是一个经典的僵局.

您需要不断读取进程输入流以确保它不会阻塞.

有一篇很好的文章解释了所有的陷阱Runtime.exec()并展示了它们周围的方法,称为"当Runtime.exec()不会"(是的,文章来自2000,但内容仍然适用!)

  • 这个答案是正确的,但它错过了一个代码示例来解决问题.看看Peter Lawrey的有用代码答案,找出为什么`waitFor()`不返回. (7认同)

Pet*_*rey 73

在等待输出完成之前,您似乎没有读取输出.仅当输出未填充缓冲区时才可以.如果是,它将等到你读取输出catch-22.

也许你有一些你不读的错误.这将使应用程序停止并等待永远等待.解决此问题的一种简单方法是将错误重定向到常规输出.

ProcessBuilder pb = new ProcessBuilder("tasklist");
pb.redirectErrorStream(true);
Process process = pb.start();
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line;
while ((line = reader.readLine()) != null)
    System.out.println("tasklist: " + line);
process.waitFor();
Run Code Online (Sandbox Code Playgroud)

  • 有关信息:ProcessBuilder是一个真正的构建器,你可以直接编写ProcessBuilder pb = new ProcessBuilder("tasklist").redirectErrorStream(true); (4认同)
  • 我宁愿使用`pb.redirectError(new File("/ dev/null"));` (3认同)
  • 应该是我认为的接受的答案,我用这个替换了我的代码,它立即起作用. (3认同)

Rol*_*Boy 40

也来自Java doc:

java.lang中

课程流程

由于某些本机平台仅为标准输入和输出流提供有限的缓冲区大小,因此无法及时写入输入流或读取子进程的输出流可能导致子进程阻塞甚至死锁.

无法从Process清除输入流的缓冲区(管道到子进程的输出流)可能导致子进程阻塞.

试试这个:

Process process = Runtime.getRuntime().exec("tasklist");
BufferedReader reader =
new BufferedReader(new InputStreamReader(process.getInputStream()));
while ((reader.readLine()) != null) {}
process.waitFor();
Run Code Online (Sandbox Code Playgroud)

  • 两个警告:(1)使用ProcessBuilder + redirectErrorStream(true),那么你是安全的.否则,(2)您需要一个线程从Process.getInputStream()读取,另一个线程从Process.getErrorStream()读取.花了大约四个小时来解决这个问题(!),又称"困难之路". (17认同)

Slo*_*pes 10

我想在之前的答案中添加一些内容,但由于我没有代表发表评论,我只想添加一个答案.这是针对用Java编程的android用户.

根据RollingBoy的帖子,这段代码几乎对我有用:

Process process = Runtime.getRuntime().exec("tasklist");
BufferedReader reader =
new BufferedReader(new InputStreamReader(process.getInputStream()));
while ((reader.readLine()) != null) {}
process.waitFor();
Run Code Online (Sandbox Code Playgroud)

在我的情况下,waitFor()没有释放,因为我正在执行一个没有返回的语句("ip adddr flush eth0").解决这个问题的一个简单方法就是确保始终在语句中返回一些内容.对我来说,这意味着执行以下操作:"ip adddr flush eth0 && echo done".你可以整天读取缓冲区,但如果没有返回任何内容,你的线程将永远不会释放它的等待.

希望有人帮助!

  • 当你没有代表评论时,_don't解决它并且无论如何评论.让它成为一个答案,并得到它的代表! (2认同)

use*_*421 5

有几种可能性:

  1. 您尚未消耗该进程的所有输出stdout
  2. 您尚未消耗该进程的所有输出stderr
  3. 该流程正在等待您的输入,您尚未提供该输入,或者您尚未关闭该流程的stdin
  4. 这个过程陷入了僵局。


Mar*_*ger 5

正如其他人提到的,您必须使用stderrstdout

与其他答案相比,从Java 1.7开始,它甚至更加容易。您不必再自己创建线程来读取stderrstdout

只需将ProcessBuilderredirectOutput结合使用方法和redirectError或即可redirectErrorStream

String directory = "/working/dir";
File out = new File(...); // File to write stdout to
File err = new File(...); // File to write stderr to
ProcessBuilder builder = new ProcessBuilder();
builder.directory(new File(directory));
builder.command(command);
builder.redirectOutput(out); // Redirect stdout to file
if(out == err) { 
  builder.redirectErrorStream(true); // Combine stderr into stdout
} else { 
  builder.redirectError(err); // Redirect stderr to file
}
Process process = builder.start();
Run Code Online (Sandbox Code Playgroud)