18

Schnipsel Mein Code:In welchen Fällen muss Future.get() throw ExecutionException oder 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(); 
} 

Wie sollte ich behandeln die InterruptedException und ExecutionException im Code?

Und in welchen Fällen werden diese Ausnahmen ausgelöst?

Antwort

27

ExecutionException und InterruptedException sind zwei sehr unterschiedliche Dinge.

ExecutionException umschließt eine beliebige Ausnahme, die vom Thread ausgeführt wird, also wenn Ihr Thread zum Beispiel eine Art von IO ausgeführt hat, die eine IOException ausgelöst hat, würde diese in eine ExecutionException gehüllt und neu gestartet werden.

Eine InterruptedException ist kein Anzeichen dafür, dass irgendetwas schief gelaufen ist. Es gibt Ihnen eine Möglichkeit, Ihren Threads mitzuteilen, wann es Zeit ist aufzuhören, damit sie ihre aktuelle Arbeit beenden und elegant beenden können. Angenommen, ich möchte, dass meine Anwendung nicht mehr ausgeführt wird, aber ich möchte nicht, dass meine Threads das löschen, was sie gerade in der Mitte von etwas tun (was passieren würde, wenn ich sie zu Daemon-Threads mache). Wenn die Anwendung heruntergefahren wird, ruft mein Code die Interrupt-Methode für diese Threads auf, die das Interrupt-Flag für sie festlegt. Wenn diese Threads das nächste Mal warten oder schlafen, überprüfen sie das Interrupt-Flag und werfen eine InterruptedException, die ich verwenden kann um aus der unendlichen Verarbeitungsschleife/Schlummerlogik der Threads herauszukommen. (Und wenn der Thread nicht wartet oder schläft, kann er das Unterbrechungsflag nur periodisch überprüfen.) Es ist also eine Instanz einer Ausnahme, die verwendet wird den Logikfluss ändern. Der einzige Grund, warum Sie es überhaupt aufzeichnen würden, ist in einem Beispielprogramm, um Ihnen zu zeigen, was passiert, oder wenn Sie ein Problem beheben, bei dem Interrupt-Logik nicht richtig funktioniert.

+0

Gibt es eine Möglichkeit zu verhindern, dass ExecutionException ausgelöst wird, wenn bei der Verarbeitung einer Aufgabe eine Ausnahme vorliegt. Auch wenn Sie die Exception in die Verarbeitung geworfen haben und diese verarbeiten, wird die Exception immer noch in ExecutionException umgewandelt und in den get-Modus geworfen. –

+0

Gibt es eine Beziehung zwischen InterruptedException und ExecutionException, nur um zu wissen, welche zuerst zu fangen ist. In der SO-Frage fängt er zuerst die InterruptedException und dann die ExecutionException ab. Wird das Verhalten dasselbe sein, wenn wir die Reihenfolge tauschen? – prime

+0

@prime: siehe https://stackoverflow.com/a/10964899/217324. Beide Ausnahmen erweitern die Ausnahme, keine ist spezifischer als die andere. Die Reihenfolge spielt in diesem Fall keine Rolle. –

6

InterruptedException wird ausgelöst, wenn interrupt im wartenden Thread aufgerufen wird, bevor die Berechnung abgeschlossen ist.

ExecutionException wird geworfen, wenn die betreffende Berechnung (Task in diesem Fall) eine Ausnahme selbst auslöst.

Wie Sie damit umgehen wollen, hängt vollständig von Ihrer Anwendung ab.

EDIT: Hier ist eine Demonstration unterbrochen zu werden:

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

Wenn ich Thread.interrupt() aufrufen, wird das Interrupt-Flag auf True festgelegt. Aber InterruptedException wird nicht ausgelöst –

+0

Es muss keine ungeprüfte Ausnahme sein. 'Callable.call()' kann alles werfen. – finnw

+0

@finnw: Absolut richtig. Tut mir leid, dass ich das verpasst habe. –

-1

Beispielcode, um drei Arten von Ausnahmen zurückzugeben.

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

Ausgang:

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: Exception ausgelöst, wenn ein Blockierungsvorgang abläuft.

Im obigen Beispiel einige Aufgaben mehr Zeit nehmen (wegen 4 Sekunden Schlaf) und Sperrbetrieb von get() auf Future

Entweder das Timeout erhöhen oder Runnable Aufgabe zu optimieren.

ExecutionException: Ausnahme ausgelöst, wenn Sie versuchen, das Ergebnis einer Aufgabe abzurufen, die durch Auslösen einer Ausnahme abgebrochen => Die Berechnung eine Ausnahme warf

In obigem Beispiel diese Exception simuliert durch ArithmeticException:/by zero

Im Allgemeinen Sie sollten es fangen, beheben Sie die Ursache, wenn es trivial ist, wie im Beispiel zitiert.

InterruptedException: Wird ausgelöst, wenn ein Thread wartet, schläft oder anderweitig belegt ist und der Thread entweder vor oder während der Aktivität unterbrochen wird.

Im obigen Beispiel wird Exception simuliert, indem der aktuelle Thread während ExecutionException unterbrochen wird.

Im Allgemeinen sollten Sie es fangen handeln Sie nicht darauf.

+0

@ downvoter, Frage erneut prüfen und beantworten. Java offizielle Gründe für die Dokumentation sind hier zitiert. –

+0

Gibt es eine Beziehung zwischen InterruptedException und ExecutionException, nur um zu wissen, welche zuerst zu fangen ist. In der SO-Frage fängt er zuerst die InterruptedException und dann die ExecutionException ab. Wird das Verhalten dasselbe sein, wenn wir die Reihenfolge tauschen? – prime

+0

InterruuptedException sollte zuerst abgefangen werden –