2009-08-15 14 views
7

Nel codice qui sotto, sto prendendo un TimeoutException dopo 100 secondi come previsto. A questo punto mi aspetto che il codice esca dal programma principale e che il programma termini, ma continua a stampare sulla console. Come faccio a interrompere l'esecuzione dell'attività dopo il timeout?Come posso restituire FutureTask dopo TimeoutException?

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); 
} 


public static void main(String[] args) { 

    try { 
     int returnCode = timedCall(new Callable<Integer>() { 
      public Integer call() throws Exception { 
       for (int i=0; i < 1000000; i++) { 
        System.out.println(new java.util.Date()); 
        Thread.sleep(1000); 
       } 
       return 0; 
      } 
     }, 100, TimeUnit.SECONDS); 
    } catch (Exception e) { 
     e.printStackTrace(); 
     return; 
    } 


} 

risposta

8

È necessario annullare il vostro compito in timeout (e interrupt suo filo). Ecco a cosa serve il metodo cancel(true). :

private static final ExecutorService THREAD_POOL = Executors.newCachedThreadPool(); 

private static <T> T timedCall(FutureTask<T> task, long timeout, TimeUnit timeUnit) throws InterruptedException, ExecutionException, TimeoutException { 
    THREAD_POOL.execute(task); 
    return task.get(timeout, timeUnit); 
} 


public static void main(String[] args) { 
     try { 
      FutureTask<Integer> task = new FutureTask<Integer>(new Callable<Integer>() { 
       public Integer call() throws Exception { 
         for (int i=0; i < 1000000; i++) { 
           if (Thread.interrupted()) return 1; 
           System.out.println(new java.util.Date()); 
           Thread.sleep(1000); 
         } 
         return 0; 
       } 
      }); 
      int returnCode = timedCall(task, 100, TimeUnit.SECONDS); 
     } catch (Exception e) { 
       e.printStackTrace(); 
       task.cancel(true); 
     } 
     return; 
} 
+1

! Task.cancelled() dovrebbe essere! IsCancelled() come djna originariamente scritto – Zed

+1

penso che sia molto meglio usare interruzioni. Innanzitutto, il tuo codice callable non ha bisogno di sapere nulla su 'task'. Secondo, quando usi varie operazioni di blocco nel tuo codice callable (come 'Thread.sleep()'), queste non reagiranno a task.isCancelled(), ma di solito reagiscono alle interruzioni. Quindi usare 'cancel (true)' e rendere il tuo codice consapevole delle interruzioni è di solito il modo migliore per farlo. (Il tuo codice sarà anche più generale, perché il meccanismo delle interruzioni è così ampiamente usato in Java) –

+0

Credo che il mio punto sia che "L'interruzione è un meccanismo cooperativo". (http://www.ibm.com/developerworks/java/library/j-jtp05236.html) –

1

Una volta che hai preso la TimeoutException, è necessario chiamare il metodo cancel (vero) del vostro compito ...

o spegnere l'ExecutorService chiamando shutdownNow() ...

o uscire la VM chiamando System.exit (0)

a seconda delle esigenze

4

vostro must richiamabile per essere in grado di fermare rapidamente, in caso di necessità.

tuo codice:

public Integer call() throws Exception { 
    for (int i=0; i < 1000000 && !task.cancelled(); i++) { 
     System.out.println(new java.util.Date()); 
     Thread.sleep(1000); // throws InterruptedException when thread is interrupted 
    } 
    return 0; 
} 

è già in grado di farlo grazie a chiamare Thread.sleep(). Il punto è che futureTask.cancel(true) interromperà l'altro thread e il tuo codice deve reagire a questa interruzione. Thread.sleep() lo fa. Se non hai utilizzato Thread.sleep() o un altro codice di blocco interrompibile, dovresti controllare da solo il e uscire il prima possibile (ad esempio lanciando new InterruptedException()) quando ritieni che sia vero.

è necessario chiamare futureTask.cancel(true); dal vostro gestore di eccezioni per annullare e interrompere il filo che corre il vostro compito.

Il mio consiglio è quello di conoscere il meccanismo di interruzione (questo è grande articolo: Dealing with InterruptedException), e usarlo.