2009-08-07 6 views
39

Au moment où j'exécuter un processus natif en utilisant les éléments suivants:java natif délai d'attente de processus

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

On suppose au lieu d'attendre que le programme retour, je souhaite mettre fin si un certain laps de temps est écoulé. Comment puis-je faire cela?

+0

S'il vous plaît trouver une bonne pratique et certains explantion ici: Wulfaz

Répondre

18

Voici comment le Plexus CommandlineUtils il fait:

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 ... donc toutes les 10 millisecondes il repose sur p.exitValue() en lançant IllegalThreadStateException pour indiquer "encore en cours"? –

+0

@ OgrePsalm33 C'est horrible, mais malheureusement, Java ne donne pas de meilleur moyen pour Java 7. Java8 donne un "p.isAlive()" – leonbloy

+1

Pourquoi la boucle? Pourquoi ne pas lancer un TimerTask qui vérifiera la "vivacité" une seule fois à l'expiration du délai? – Stan

2

Vous auriez besoin d'un fil 2. qui interrompt le fil qui appelle .waitFor(); Certains synchronisation non trivial sera nécessaire pour le rendre robuste, mais les bases sont:

TimeoutThread:

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

ProcessThread:

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

Toutes les autres réponses sont correctes, mais il peut être plus robuste et efficace en utilisant FutureTask.

Par exemple,

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 vous faites cela à plusieurs reprises, le pool de threads est plus efficace, car il met en cache les fils.

+0

Le délai d'expiration du handle ici pourrait être un peu plus robuste pour un exemple. J'ai un couple de mécanismes que j'utilise, mais pour le cas le plus simple, utilisez quelque chose comme: 'catch (TimeoutException e) {System.exit (-1);}' –

+0

L'argument Type ne peut pas être de type primitif. Veuillez remplacer 'int' par' Integer'. – naXa

6

Qu'en est-il juste un peu modifié Groovy façon

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

selon mon exigence. le temps d'arrêt est de 10 secondes ici. le processus est détruit après 10 secondes s'il ne sort pas.

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 vous utilisez Java 8, vous pouvez simplement utiliser la nouvelle waitFor with timeout:

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