2009-08-07 84 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 
}