18

mio frammento di codice:In quali casi si fa Future.get() un tiro ExecutionException o InterruptedException

ExecutorService executor = Executors.newSingleThreadExecutor(); 
try { 
    Task t = new Task(response,inputToPass,pTypes,unit.getInstance(),methodName,unit.getUnitKey()); 
    Future<SCCallOutResponse> fut = executor.submit(t); 
    response = fut.get(unit.getTimeOut(),TimeUnit.MILLISECONDS); 
} catch (TimeoutException e) { 
    // if the task is still running, a TimeOutException will occur while fut.get() 
    cat.error("Unit " + unit.getUnitKey() + " Timed Out"); 
    response.setVote(SCCallOutConsts.TIMEOUT); 
} catch (InterruptedException e) { 
    cat.error(e); 
} catch (ExecutionException e) { 
    cat.error(e); 
} finally { 
    executor.shutdown(); 
} 

come devo gestire la InterruptedException e ExecutionException nel codice?

E in quali casi vengono lanciate queste eccezioni?

risposta

27

ExecutionException e InterruptedException sono due cose molto diverse.

ExecutionException avvolge qualsiasi eccezione il thread che viene eseguito, quindi se il thread, ad esempio, eseguiva una sorta di I/O che causava il lancio di una IOException, veniva incapsulato in ExecutionException e retrocesso.

Un InterruptedException non è un segno che qualcosa è andato storto. È lì per darti il ​​modo di far sapere ai tuoi thread quando è ora di smettere, in modo che possano finire il loro lavoro attuale e uscire con grazia. Diciamo che voglio che la mia applicazione smetta di funzionare, ma non voglio che i miei thread facciano cadere quello che stanno facendo nel bel mezzo di qualcosa (cosa che succederebbe se li avessi creati con dei thread daemon). Quindi, quando l'applicazione viene arrestata, il mio codice chiama il metodo di interrupt su questi thread, che imposta su di essi il flag di interrupt, e la prossima volta che quei thread sono in attesa o dormono controllano il flag di interrupt e lanciano un InterruptedException, che posso usare per salvare qualsiasi logica di elaborazione/sonno a ciclo infinito in cui i thread sono impegnati. (E se il thread non attende o non dorme, può controllare periodicamente la flag di interrupt.) Quindi è un'istanza di un'eccezione usata per cambiare il flusso logico. L'unico motivo per cui è necessario registrarlo è in un programma di esempio per mostrarti cosa sta succedendo o se stai eseguendo il debug di un problema in cui la logica dell'interrupt non funziona correttamente.

+0

C'è un modo per impedire l'esecuzione di ExecutionException, quando c'è un'eccezione nell'elaborazione di un'attività. Anche se l'Eccezione è stata rilevata durante l'elaborazione e gestita, l'eccezione viene comunque applicata a ExecutionException e la getta nel get. –

+0

Esiste una relazione tra InterruptedException ed ExecutionException, solo per sapere quale prendere prima. Nella domanda SO cattura prima InterruptedException e poi ExecutionException. Il comportamento sarà lo stesso se scambiamo l'ordine? – prime

+0

@prime: vedere https://stackoverflow.com/a/10964899/217324. Entrambe le eccezioni estendono Eccezione, nessuna delle due è più specifica dell'altra. L'ordine non ha importanza in questo caso. –

6

InterruptedException verrà generato se interrupt viene chiamato sul thread in attesa prima del completamento del calcolo.

ExecutionException verrà generato se il calcolo coinvolto (Task in questo caso) genera un'eccezione stessa.

Come si desidera gestire questo dipenderà interamente dalla vostra applicazione.

EDIT: Ecco una dimostrazione di essere interrotti:

import java.util.concurrent.*; 

public class Test 
{ 
    public static void main(String[] args) throws Exception 
    { 
     ExecutorService executor = Executors.newFixedThreadPool(2); 
     Future<String> future = executor.submit(new SlowCallable()); 
     executor.submit(new Interruptor(Thread.currentThread())); 
     try 
     { 
      System.out.println(future.get()); 
     } 
     catch (InterruptedException e) 
     { 
      System.out.println("I was interrupted"); 
     } 
    } 

    private static class Interruptor implements Callable<String> 
    { 
     private final Thread threadToInterrupt; 

     Interruptor(Thread threadToInterrupt) 
     { 
      this.threadToInterrupt = threadToInterrupt; 
     } 

     public String call() throws Exception 
     { 
      Thread.sleep(2000); 
      threadToInterrupt.interrupt(); 
      return "interrupted other thread"; 
     } 
    } 

    private static class SlowCallable implements Callable<String> 
    { 
     public String call() throws Exception 
     { 
      Thread.sleep(5000); 
      return "finished"; 
     } 
    } 
} 
+0

se si chiama Thread.interrupt(), il flag di interrupt è impostato su true. Ma InterruptedException non viene lanciata –

+0

Non deve essere un'eccezione non controllata. 'Callable.call()' può lanciare qualsiasi cosa. – finnw

+0

@finnw: assolutamente giusto. Mi dispiace averlo perso. –

-1

Codice di esempio per restituire tre tipi di eccezioni.

import java.util.concurrent.*; 
import java.util.*; 

public class ExceptionDemo{ 
    public static void main(String args[]){ 
     int poolSize=1; 
     int maxPoolSize=1; 
     int queueSize=30; 
     long aliveTive=60; 
     ArrayBlockingQueue<Runnable> queue= new ArrayBlockingQueue<Runnable>(queueSize); 
     ThreadPoolExecutor executor= new ThreadPoolExecutor(poolSize,maxPoolSize,aliveTive, 
         TimeUnit.MILLISECONDS,queue); 
     List<Future> futures = new ArrayList<Future>(); 
     for (int i=0; i < 5; i++){ 
      futures.add(executor.submit(new RunnableEx())); 
     } 
     for (Iterator it = futures.iterator(); it.hasNext();){ 
      try { 
       Future f = (Future)it.next(); 
       f.get(4000,TimeUnit.MILLISECONDS); 
      }catch(TimeoutException terr){ 
       System.out.println("Timeout exception"); 
       terr.printStackTrace(); 
      } 
      catch(InterruptedException ierr){ 
       System.out.println("Interrupted exception:"); 
       ierr.printStackTrace(); 
      }catch(ExecutionException err){ 
       System.out.println("Exeuction exception:"); 
       err.printStackTrace(); 
       Thread.currentThread().interrupt(); 
      } 
     } 
     executor.shutdown(); 
    } 
} 

class RunnableEx implements Runnable{ 
    public void run() { 
     // code in here 
     System.out.println("Thread name:"+Thread.currentThread().getName()); 
     try{ 
      Random r = new Random(); 
      if (r.nextInt(2) == 1){ 
       Thread.sleep(2000); 
      }else{ 
       Thread.sleep(4000); 
      } 
      System.out.println("eee:"+1/0); 
     }catch(InterruptedException irr){ 
      irr.printStackTrace(); 
     } 
    } 
} 

uscita:

Thread name:pool-1-thread-1 
Timeout exception 
Thread name:pool-1-thread-1 
java.util.concurrent.TimeoutException 
     at java.util.concurrent.FutureTask.get(FutureTask.java:201) 
     at ExceptionDemo.main(ExceptionDemo.java:20) 
Thread name:pool-1-thread-1 
Exeuction exception: 
java.util.concurrent.ExecutionException: java.lang.ArithmeticException:/by zero 
     at java.util.concurrent.FutureTask.report(FutureTask.java:122) 
     at java.util.concurrent.FutureTask.get(FutureTask.java:202) 
     at ExceptionDemo.main(ExceptionDemo.java:20) 
Caused by: java.lang.ArithmeticException:/by zero 
     at RunnableEx.run(ExceptionDemo.java:49) 
     at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471) 
     at java.util.concurrent.FutureTask.run(FutureTask.java:262) 
     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) 
     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) 
     at java.lang.Thread.run(Thread.java:744) 
Interrupted exception: 
java.lang.InterruptedException 
     at java.util.concurrent.FutureTask.awaitDone(FutureTask.java:400) 
     at java.util.concurrent.FutureTask.get(FutureTask.java:199) 
     at ExceptionDemo.main(ExceptionDemo.java:20) 
Timeout exception 
java.util.concurrent.TimeoutException 
     at java.util.concurrent.FutureTask.get(FutureTask.java:201) 
Thread name:pool-1-thread-1 
     at ExceptionDemo.main(ExceptionDemo.java:20) 
Thread name:pool-1-thread-1 
Timeout exception 
java.util.concurrent.TimeoutException 
     at java.util.concurrent.FutureTask.get(FutureTask.java:201) 
     at ExceptionDemo.main(ExceptionDemo.java:20) 

TimeoutException: eccezione generata quando un blocco timeout dell'operazione.

Nel precedente esempio, alcune attività stanno prendendo più tempo (a causa di 4 secondi il sonno) e bloccando il funzionamento del get() su Future

O aumentare il timeout o ottimizzare compito Runnable.

ExecutionException: eccezione generata quando si tenta di recuperare il risultato di un compito che interrotta da un'eccezione => Il calcolo ha generato un'eccezione

Nell'esempio sopra, questo Exception viene simulato attraverso ArithmeticException:/by zero

Generalmente, dovresti catturare la causa principale se è banale come citato nell'esempio.

: generato quando un thread è in attesa, inattivo o occupato in altro modo e il thread viene interrotto, prima o durante l'attività.

Nell'esempio sopra, questo Exception viene simulato interrompendo il thread corrente durante ExecutionException.

Generalmente, dovresti prenderlo non agire su di esso.

+0

@downvoter, ricontrolla domanda e risposta. Le ragioni della documentazione ufficiale di Java sono citate qui. –

+0

Esiste una relazione tra InterruptedException ed ExecutionException, solo per sapere quale prendere prima. Nella domanda SO cattura prima InterruptedException e poi ExecutionException. Il comportamento sarà lo stesso se scambiamo l'ordine? – prime

+0

InterruuptedException deve essere catturato per primo –

Problemi correlati