2009-08-07 83 views
39

目前我使用下面的执行本机进程:Java本机进程超时

java.lang.Process process = Runtime.getRuntime().exec(command); 
int returnCode = process.waitFor(); 

假设,而不是等待程序返回我想终止,如果在一定的时间量已过去。我该怎么做呢?

+0

请找到一个很好的做法,一些explantion这里: Wulfaz 2013-07-16 13:25:31

回答

18

这是丛CommandlineUtils是怎么做的:

Process p; 

p = cl.execute(); 

... 

if (timeoutInSeconds <= 0) 
{ 
    returnValue = p.waitFor(); 
} 
else 
{ 
    long now = System.currentTimeMillis(); 
    long timeoutInMillis = 1000L * timeoutInSeconds; 
    long finish = now + timeoutInMillis; 
    while (isAlive(p) && (System.currentTimeMillis() < finish)) 
    { 
     Thread.sleep(10); 
    } 
    if (isAlive(p)) 
    { 
     throw new InterruptedException("Process timeout out after " + timeoutInSeconds + " seconds"); 
    } 
    returnValue = p.exitValue(); 
} 

public static boolean isAlive(Process p) { 
    try 
    { 
     p.exitValue(); 
     return false; 
    } catch (IllegalThreadStateException e) { 
     return true; 
    } 
} 
+8

Ewwww ...所以每10毫秒依靠p.exitValue()抛出IllegalThreadStateException表示“仍在运行”? – 2012-04-09 22:02:37

+0

@ OgrePsalm33这太糟糕了,但是令人遗憾的是,Java没有提供更好的Java 7版本。Java8给出了“p.isAlive()” – leonbloy 2014-05-16 18:17:44

+1

为什么是循环?为什么不运行一个TimerTask,它将在超时过期后仅检查一次“活性”? – Stan 2015-06-30 22:21:23

2

你需要一个2线程中断调用.waitFor()线程;将需要 一些不平凡的同步,使之强劲,但基本是:

TimeoutThread:

Thread.sleep(timeout); 
processThread.interrupt(); 

ProcessThread:

try { 
     proc.waitFor(); 
    } catch (InterruptedException e) { 
     proc.destroy(); 
    } 
49

所有其他的反应是正确的,但它可以制成使用FutureTask更健壮,更高效。

例如,

private static final ExecutorService THREAD_POOL 
    = Executors.newCachedThreadPool(); 

private static <T> T timedCall(Callable<T> c, long timeout, TimeUnit timeUnit) 
    throws InterruptedException, ExecutionException, TimeoutException 
{ 
    FutureTask<T> task = new FutureTask<T>(c); 
    THREAD_POOL.execute(task); 
    return task.get(timeout, timeUnit); 
} 

try { 
    int returnCode = timedCall(new Callable<Integer>() { 
     public Integer call() throws Exception { 
      java.lang.Process process = Runtime.getRuntime().exec(command); 
      return process.waitFor(); 
     } 
    }, timeout, TimeUnit.SECONDS); 
} catch (TimeoutException e) { 
    // Handle timeout here 
} 

如果这样反反复复,线程池是更有效,因为它缓存的线程。

+0

这里的句柄超时对于一个例子来说可能更健壮一些。我有一些我使用的机制,但是对于最简单的情况,使用如下形式:'catch(TimeoutException e){System.exit(-1);}' – 2012-11-10 15:49:19

+0

类型参数不能是原始类型。请用'Integer'替换int。 – naXa 2014-09-22 15:15:23

6

怎么样的Groovy方式

public void yourMethod() { 
    ... 
    Process process = new ProcessBuilder(...).start(); 
    //wait 5 secs or kill the process 
    waitForOrKill(process, TimeUnit.SECONDS.toMillis(5)); 
    ... 
} 

public static void waitForOrKill(Process self, long numberOfMillis) { 
    ProcessRunner runnable = new ProcessRunner(self); 
    Thread thread = new Thread(runnable); 
    thread.start(); 
    runnable.waitForOrKill(numberOfMillis); 
} 

protected static class ProcessRunner implements Runnable { 
    Process process; 
    private boolean finished; 

    public ProcessRunner(Process process) { 
     this.process = process; 
    } 

    public void run() { 
     try { 
      process.waitFor(); 
     } catch (InterruptedException e) { 
      // Ignore 
     } 
     synchronized (this) { 
      notifyAll(); 
      finished = true; 
     } 
    } 

    public synchronized void waitForOrKill(long millis) { 
     if (!finished) { 
      try { 
       wait(millis); 
      } catch (InterruptedException e) { 
       // Ignore 
      } 
      if (!finished) { 
       process.destroy(); 
      } 
     } 
    } 
} 
4

根据我的要求只是修改了一下。超时在这里是10秒。如果没有退出,过程将在10秒后被破坏。

public static void main(String arg[]) 
{ 


    try{ 

    Process p =Runtime.getRuntime().exec("\"C:/Program Files/VanDyke Software/SecureCRT/SecureCRT.exe\""); 
    long now = System.currentTimeMillis(); 
    long timeoutInMillis = 1000L * 10; 
    long finish = now + timeoutInMillis; 
    while (isAlive(p)) 
    { 
     Thread.sleep(10); 
     if (System.currentTimeMillis() > finish) { 

      p.destroy(); 

     } 



    } 

    } 
    catch (Exception err) { 
     err.printStackTrace(); 

     } 
} 

public static boolean isAlive(Process p) { 
    try 
    { 
     p.exitValue(); 
     return false; 
    } catch (IllegalThreadStateException e) { 
     return true; 
    } 
} 
14

如果您使用的是Java 8,你可以简单地使用新waitFor with timeout

Process p = ... 
if(!p.waitFor(1, TimeUnit.MINUTE)) { 
    //timeout - kill the process. 
    p.destroy(); // consider using destroyForcibly instead 
}