java本地进程超时

目前我使用以下方法执行本机进程:

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

假设不是等待程序返回,而是希望在经过一定时间后终止。 我如何做到这一点?

这是Plexus 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; } } 

所有其他答案都是正确的,但使用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 } 

如果重复执行此操作,线程池会更高效,因为它会caching线程。

如果您使用的是Java 8,那么可以简单地使用带有超时的新的waitFor :

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

那么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(); } } } } 

只是根据我的要求修改了一下。 超时时间在这里是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; } } 

你需要一个2线程来中断调用.waitFor()的线程。 一些不平凡的同步将需要使其健壮,但基本是:

TimeoutThread:

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

ProcessThread:

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