2009-08-07 16 views
39

Al momento ho eseguire un processo nativo utilizzando il seguente:Java Native processo timeout

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

Supponiamo invece di aspettare che il programma per tornare desidero terminare se una certa quantità di tempo è trascorso. Come faccio a fare questo?

+0

Si prega di trovare una buona pratica e un po 'explantion qui: Wulfaz

risposta

18

Questo è come il plesso CommandlineUtils fa:

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 ... così ogni 10 millisecondi si basa su p.exitValue() che lancia IllegalThreadStateException per indicare "ancora in esecuzione"? –

+0

@ OgrePsalm33 È terribile, ma purtroppo Java non fornisce un modo migliore per Java 7. Java8 fornisce un "p.isAlive()" – leonbloy

+1

Perché il ciclo? Perché non eseguire un TimerTask che verificherà la "vitalità" solo una volta al termine della scadenza? – Stan

2

avresti bisogno di un 2. filo che interrompe il thread che chiama .waitFor(); Alcuni di sincronizzazione non banale sarà necessaria per renderla robusta, ma le basi sono:

TimeoutThread:

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

ProcessThread:

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

Tutte le altre risposte sono corrette, ma può essere fatto più robusto ed efficiente usando FutureTask.

Per esempio,

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 
} 

Se si esegue questa operazione più volte, il pool di thread è più efficiente perché memorizza nella cache i fili.

+0

Il timeout della maniglia qui potrebbe essere un po 'più robusto per un esempio. Ho un paio di meccanismi che uso, ma per il caso più semplice, usare qualcosa come: 'catch (TimeoutException e) {System.exit (-1);}' –

+0

L'argomento Type non può essere di tipo primitivo. Per favore sostituisci 'int' con' Integer'. – naXa

6

cosa circa il modo in cui 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

appena modificato un po 'secondo la mia esigenza. il timeout è di 10 secondi qui. il processo viene distrutto dopo 10 secondi se non si sta per uscire.

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

Se stai usando Java 8 si può semplicemente utilizzare il nuovo waitFor with timeout:

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