2009-08-07 20 views
39

W tej chwili wykonać natywną proces przy użyciu następujących:Java Native Timeout Process

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

Załóżmy, zamiast czekać na powrót do programu pragnę zakończyć, gdy upłynie określony czas. Jak mam to zrobic?

+0

Proszę znaleźć dobrą praktykę i trochę WYJAŚNIENIE tutaj: Wulfaz

Odpowiedz

18

ten sposób splotu CommandlineUtils robi:

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 ... więc co 10 milisekund opiera się na p.exitValue() rzucając IllegalThreadStateException wskazać "nadal działa"? –

+0

@ OgrePsalm33 To okropne, ale niestety Java nie daje lepszego sposobu na Java 7. Java8 daje "p.isAlive()" – leonbloy

+1

Dlaczego ta pętla? Dlaczego nie uruchamiać TimerTask, który sprawdzi "żywotność" tylko raz po wygaśnięciu limitu czasu? – Stan

2

Byłbyś potrzebują 2. wątek, który przerywa wątek, który wywołuje .waitFor(); będą potrzebne Niektóre non trywialny synchronizacja, aby wytrzymała, ale podstawy są:

TimeoutThread:

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

ProcessThread:

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

Wszystkie inne odpowiedzi są poprawne, ale może być wykonana bardziej niezawodne i wydajniejsze dzięki FutureTask.

Na przykład

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 
} 

Jeśli to zrobić wielokrotnie, basen wątek jest bardziej efektywne, ponieważ buforuje wątki.

+0

Limit czasu uchwytów może być na przykład trochę bardziej solidny. Mam kilka mechanizmów, których używam, ale w najprostszym przypadku użyj czegoś takiego jak: catch (TimeoutException e) {System.exit (-1);} ' –

+0

Argument typu nie może być typu pierwotnego. Proszę zastąpić 'int' z' Integer'. – naXa

6

Co o sposobie 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

tylko zmodyfikowane nieco według moich wymagań. limit czasu wynosi tutaj 10 sekund. proces ulega zniszczeniu po 10 sekundach, jeśli nie jest zamykany.

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

Jeśli używasz Java 8 można po prostu użyć nowego waitFor with timeout:

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