2009-08-07 16 views
39

Im Moment ausführen ich einen nativen Prozess mit dem folgenden:Java Native Prozess Timeout

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

Angenommen, statt für das Programm des Wartens zurück ich, wenn eine bestimmte Zeit verstrichen ist, beenden wollen. Wie mache ich das?

+0

Hier finden Sie eine gute Praxis und einige explantion hier: Wulfaz

Antwort

18

Dies ist, wie der Plexus CommandlineUtils tut es:

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 ... also alle 10 Millisekunden hängt es ab, dass p.exitValue() IllegalThreadStateException wirft "immer noch laufen" anzeigen? –

+0

@ OgrePsalm33 Es ist schrecklich, aber leider Java bietet keinen schöneren Weg bis zu Java 7. Java8 gibt eine "p.isAlive()" – leonbloy

+1

Warum die Schleife? Warum nicht eine TimerTask ausführen, die die "Lebendigkeit" nur einmal nach Ablauf der Zeitüberschreitung überprüft? – Stan

2

Sie einen 2. Thread bräuchten, der den Thread unterbricht die .waitFor() aufruft; Einige nicht trivial Synchronisation wird benötigt, um es robuster zu machen, aber die Grundlagen sind:

TimeoutThread:

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

Process:

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

Alle anderen Antworten richtig sind, aber es kann gemacht werden, robuster und effizienter mit FutureTask.

Zum Beispiel

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 
} 

Wenn Sie dies immer wieder tun, ist der Thread-Pool effizienter, da sie die Fäden zwischenspeichert.

+0

Das Handle Timeout könnte hier ein wenig robuster sein. Ich habe ein paar Mechanismen, die ich verwende, aber für den einfachsten Fall, verwenden Sie etwas wie: 'catch (TimeoutException e) {System.exit (-1);}' –

+0

Typ Argument kann nicht von primitiven Typ sein. Bitte ersetzen Sie "int" durch "Integer". – naXa

6

Was ist mit dem Groovy Weg

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

nur ein bisschen nach meiner Anforderung geändert. Die Zeitüberschreitung beträgt hier 10 Sekunden. Der Prozess wird nach 10 Sekunden zerstört, wenn er nicht beendet wird.

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

Wenn Sie Java 8 verwenden sind können Sie einfach verwenden die neue waitFor with timeout:

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