使父线程等到子线程完成或超时

时间:2010-07-20 17:16:20

标签: java multithreading

我在unix上运行Java进程。

我需要运行一个外部进程,该进程由主进程使用ProcessBuilder生成。主进程等待外部进程完成,然后生成下一个外部进程。我一直在这里工作。

public static void main(String[] args) { for(...) { int exitVal = runExternalProcess(args); if(exitVal !=0) { failedProcess.add(args); } } }

private int runExternalProcess(String[] args) { ProcessBuilder pb = new ProcessBuilder(args[0], args[1], args[2]); pb.redirectErrorStream(true); Process proc = pb.start(); BufferedReader br = new BufferedReader(new InputStreamReader( proc.getInputStream())); String line = null; while ( (line = br.readLine()) != null) LOG.log(Level.SEVERE, line);

//Main thread waits for external process to complete.
//What I need to do is. 
// If proc.executionTime() > TIMEOUT
//     kill proc;         
int exitVal = proc.waitFor();

proc.getInputStream().close();
proc.getOutputStream().close();
proc.getErrorStream().close();

return exitVal;

}

我无法弄清楚的是,如何做到这一点。对于某些输入,外部进程挂起,在这种情况下,我想等待一个设置的超时时间,如果那时外部进程没有完成,只需将其终止并将控制权返回给主进程(以及退出值以便我可以跟踪失败的进程),以便可以启动下一个外部进程。

我尝试使用proc.wait(TIMEOUT)然后使用proc.exitValue();获取退出值,但无法使其正常工作。

谢谢!

1 个答案:

答案 0 :(得分:5)

你可以做Thread.join(long)或Thread.join(long,int)并在单独的线程中启动进程。

添加一些代码。 (工作但未完全测试所有角落情况)

  public class Test {

     public static void main(String[] args) throws Throwable  {
        for(int i = 0; i < 3; i++) {
           ProcessRunner pr = new ProcessRunner(args);
           pr.start();
           // wait for 100 ms
           pr.join(100);
           // process still going on? kill it!
           if(!pr.isDone())  {
              System.err.println("Destroying process " + pr);
              pr.abort();
           }
        }
     }

     static class ProcessRunner extends Thread  {
        ProcessBuilder b;
        Process p;
        boolean done = false;

        ProcessRunner(String[] args)  {
           super("ProcessRunner " + args); // got lazy here :D
           b = new ProcessBuilder(args);
        }

        public void run()   {
           try   {
              p = b.start();

              // Do your buffered reader and readline stuff here

              // wait for the process to complete
              p.waitFor();
           }catch(Exception e) {
              System.err.println(e.getMessage());
           }finally {
              // some cleanup code
              done = true;
           }
        }

        int exitValue() throws IllegalStateException  {
           if(p != null)  {
              return p.exitValue();
           }         
           throw new IllegalStateException("Process not started yet");
        }

        boolean isDone()  {
           return done;
        }

        void abort()   {
           if(! isDone()) {
              // do some cleanup first
              p.destroy();
           }
        }
     }
  }