【问题标题】:Process.waitFor() a threadProcess.waitFor() 一个线程
【发布时间】:2013-03-18 16:58:06
【问题描述】:

在运行外部脚本时,我想同时或分别读取该脚本的 ErrorStream 和 OutputStream,然后进一步处理它们。因此,我为其中一个流启动了Thread。不幸的是,Process 似乎并没有将waitForThread 终止,而是在非线程流没有进一步输入之后返回。

简而言之,这就是我正在做的事情:

ProcessBuilder pb = new ProcessBuilder(script);  
final Process p = pb.start();  

new Thread(new Runnable() {  
  public void run() {
    BufferedReader br = new BufferedReader(new InputStreamReader(p.getErrorStream()));
    ...read lines and process them...
  }
}).start();

BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream()));
...read lines and process them...

int exitValue = p.waitFor();
p.getOutputStream().close();
return exitValue;

waitForThread有可能被终止吗?

【问题讨论】:

  • 也许只使用Commons Exec - 没有用重新发明轮子。
  • 如果您发布您的真实代码会很有帮助。两件事,你永远不会启动你的输入流阅读器线程;并且您不应该在进程输出流完成之前关闭它。
  • @Perception :抱歉,代码不完整,因此有缺陷。我已经在上面更正了。

标签: java multithreading process processbuilder inputstreamreader


【解决方案1】:

您可以使用Thread.join(...) 等待Thread 完成。请注意,如果当前线程在您等待的线程完成之前收到中断,则调用将抛出 InterruptedException

【讨论】:

    【解决方案2】:

    这是执行您想做的事情的一般代码。在这种情况下,既有输入也有输出:我将someFile 输送到流程中,并将输出输送到System.outFiles.copy()ByteStreams.copy() 只是将InputStream 连接到OutputStream 的Guava 便捷方法。然后我们等待命令完成。

    final Process pr = Runtime.getRuntime().exec(cmd);
    
    new Thread() {
        public void run() {
            try (OutputStream stdin = pr.getOutputStream()) {
                Files.copy(someFile, stdin);
            } 
            catch (IOException e) { e.printStackTrace(); }
        }
    }.start();
    
    new Thread() {
        public void run() {
            try (InputStream stdout = pr.getInputStream()) {
                ByteStreams.copy(stdout, System.out);
            } 
            catch (IOException e) { e.printStackTrace(); }  
        }
    }.start();              
    
    int exitVal = pr.waitFor();
    if( exitVal == 0 )
        System.out.println("Command succeeded!");
    else    
        System.out.println("Exited with error code " + exitVal);
    

    如果您在 Java 7 之前使用 try-with-resources 块运行,则更详细的版本:

    final Process pr = Runtime.getRuntime().exec(cmd);
    
    new Thread() {
        public void run() {
            OutputStream stdin = null;
            try {
                Files.copy(someFile, stdin = pr.getOutputStream());
            } 
            catch (IOException e) { e.printStackTrace(); }
            finally {
                if( stdin != null ) {
                    try { stdin.close(); } 
                    catch (IOException e) { e.printStackTrace(); }
                }
            }               
        }
    }.start();
    
    new Thread() {
        public void run() {
            InputStream stdout = null;
            try {
                ByteStreams.copy(stdout = pr.getInputStream(), System.out);
            } 
            catch (IOException e) { e.printStackTrace(); }
            finally {
                if( stdout != null ) {
                    try { stdout.close(); } 
                    catch (IOException e) { e.printStackTrace(); }
                }
            }               
        }
    }.start();              
    
    int exitVal = pr.waitFor();
    if( exitVal == 0 )
        System.out.println("Command succeeded!");
    else    
        System.out.println("Exited with error code " + exitVal);
    

    【讨论】:

    • 感谢您的回答。不幸的是,使用“Commons Exec”对我不起作用。线程流也没有waitFor。但是我可以使用上面斯蒂芬的解决方案来解决这个问题。
    • 不确定您在我的回答中在哪里看到 Commons Exec。 Process 及其 waitFor() 方法在标准 Java 中可用。
    • 非常有用的答案(第一个代码),但我不得不使用“IOUtils”而不是“ByteStreams”(第二个线程)。
    • 你好Andrew,你认为需要关闭流程流(变量stdout)吗?一旦进程退出,流将自动关闭,不是吗?不确定,所以问你。
    • 如果这是进程中运行的唯一代码,则不必这样做,但通常最好这样做,因为如果与其他代码一起执行此操作,则会导致内存泄漏。
    猜你喜欢
    • 2011-01-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-10-05
    • 2012-11-01
    • 1970-01-01
    相关资源
    最近更新 更多