2009-08-07 12 views
39

En el momento en que ejecute un proceso nativo utilizando la siguiente:java Proceso de tiempo de espera nativa

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

Supongamos que en lugar de esperar a que el programa para volver Deseo terminará si ha transcurrido un cierto periodo de tiempo. ¿Cómo hago esto?

+0

Por favor, encontrar una buena práctica y algo explantion aquí: Wulfaz

Respuesta

18

Así es como el plexo CommandlineUtils lo hace:

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 ... así que cada 10 milisegundos se basa en p.exitValue() lanzando IllegalThreadStateException para indicar "todavía en ejecución"? –

+0

@ OgrePsalm33 Es horrible, pero lamentablemente Java no da una mejor forma de llegar a Java 7. Java8 da un "p.isAlive()" – leonbloy

+1

¿Por qué el bucle? ¿Por qué no ejecutar un TimerTask que verificará "aliveness" solo una vez al vencimiento del tiempo de espera? – Stan

2

se necesitaría una 2. hilo que interrumpe el hilo que llama .waitFor(); Se necesitará Algunos de sincronización no trivial para que sea robusta, pero los fundamentos son:

TimeoutThread:

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

ProcessThread:

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

Todas las otras respuestas son correctas pero se pueden hacer más robusto y eficiente usando FutureTask.

Por ejemplo,

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 
} 

Si haces esto en varias ocasiones, el grupo de subprocesos es más eficiente, ya que almacena en caché los hilos.

+0

El tiempo de espera del controlador aquí podría ser un poco más robusto para un ejemplo. Tengo un par de mecanismos que uso, pero para el caso más simple, use algo como: 'catch (TimeoutException e) {System.exit (-1);}' –

+0

El argumento de tipo no puede ser de tipo primitivo. Reemplace 'int' con' Entero'. – naXa

6

que hay de como 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

acaba de modificar un poco de acuerdo a mi requerimiento. el tiempo de espera es de 10 segundos aquí. proceso se destruye después de 10 segundos si no está saliendo.

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

Si está utilizando Java 8 simplemente podría utilizar el nuevo waitFor with timeout:

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