2011-09-19 101 views
6

我正在使用Java的ProcessBuilder启动子进程,这是另一个必须在单独的JVM中运行的Java程序。从Java启动的子进程使用waitFor完成,但流并未终止

我启动两个线程从Process读取stdout和stderr流,以便在流缓冲区已满时不会挂起。 对Process.waitFor的调用返回,但流没有终止。

我使用看起来像代码(命令是一个字符串列表):

ProcessBuilder pb = new ProcessBuilder(command); 

final Process p = pb.start(); 
final ByteArrayOutputStream outStream = new ByteArrayOutputStream(); 
final ByteArrayOutputStream errStream = new ByteArrayOutputStream(); 

Thread outputThread = new Thread() { 
    @Override 
    public void run() { 
     try { 
      IOUtils.copy(p.getInputStream(), outStream); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
    }; 
}; 
outputThread.start(); 

Thread errorThread = new Thread() { 
    @Override 
    public void run() { 
     try { 
      IOUtils.copy(p.getErrorStream(), errStream); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
    }; 
}; 
errorThread.start(); 

int returncode = p.waitFor(); 
outputThread.join(); 
errorThread.join(); 

如果我跑别的东西,比如“Java的版本”或“目录”或什么的,代码工作正常。 我有权访问我尝试运行的Java代码,但我从来没有听说您应该在System.out上调用close()。

+0

你可能有兴趣在我关于关闭进程问题溪流合适:http://stackoverflow.com/questions/7065067/how-to-close-std -stream-from-java-lang-process-appropriate 另一个有用的链接:http://mark.koli.ch/2011/01/leaky-pipes-remember-to-close-your-streams-when-using- javas-runtimegetruntimeexec.html –

+0

如果我在'join()'调用之前使用'IOUtils.closeQuietly'或者甚至在流上调用'close()',那么程序会挂在那个调用上。 –

+0

这很可能是因为'IOUtils.copy(in,out)'使用'InputStream.read(byte [])'并且阻塞并等待传入​​数据。因此线程永远在运行,因此join()会永远等待。在给定超时超过后,您必须强制关闭。请尝试一个实施,就像我在我给你的链接回复中发布的那样。我敢打赌它可以在这里处理。 –

回答

0

正如我从this website知道的那样,您必须自己关闭Process对象中的所有std-streams。无论之前是否使用过。这似乎与G1垃圾回收器(Java 7 afaik以来的默认值)高度相关,即使在未明确关闭时也会保持管道打开 - 即使子进程已终止。

我对这里的内部不熟悉,但我发布在my answer的代码对于我的问题在24/7系统上很好地工作,调用GhostScript和其他人很多。

在作这样的声明,你必须关闭进程STD-流明确的其他问题和解答: