Frage

Sagen Sie, dass ich den folgenden Code haben:

ExecutorService executor = Executors.newSingleThreadExecutor();
executor.execute(myRunnable);

Nun, wenn myRunnable eine RuntimeExcpetion wirft, wie kann ich es fangen? Eine Möglichkeit wäre, auf meine eigene ThreadFactory Implementierung liefern newSingleThreadExecutor() und benutzerdefinierte uncaughtExceptionHandlers für die Threads gesetzt, die aus ihm heraus kommen. Eine weitere Möglichkeit wäre myRunnable zu einem lokalen (anonym) Runnable wickeln, die einen Try-Catch -Block enthält. Vielleicht gibt es andere ähnliche Abhilfen zu. Aber ... irgendwie das fühlt sich schmutzig, ich glaube, dass es nicht so kompliziert sein soll. Gibt es eine saubere Lösung?

War es hilfreich?

Lösung

Die saubere Abhilfe ist ExecutorService.submit() statt execute() zu verwenden. Dies gibt Ihnen eine Future, die Sie verwenden können, um das Ergebnis oder eine Ausnahme von der Aufgabe zu erhalten:

ExecutorService executor = Executors.newSingleThreadExecutor();
Runnable task = new Runnable() {
  public void run() {
    throw new RuntimeException("foo");
  }
};

Future<?> future = executor.submit(task);
try {
  future.get();
} catch (ExecutionException e) {
  Exception rootException = e.getCause();
}

Andere Tipps

Dekorieren Sie den runnable in einem anderen runnable, die die Laufzeit Ausnahmen abfängt und behandelt sie:

public class REHandler implements Runnable {
    Runnable delegate;
    public REHandler (Runnable delegate) {
        this.delegate = delegate;
    }
    public void run () {
        try {
            delegate.run ();
        } catch (RuntimeException e) {
            ... your fancy error handling here ...
        }
    }
}

executor.execute(new REHandler (myRunnable));

Warum rufen Sie nicht ExecutorService#submit() erhalten Sie die Future zurück und dann behandeln mögliche Ausnahmen selbst wenn Sie anrufen? Future#get() ?

skaffman ist richtig, dass mit submit der sauberste Ansatz. Ein alternativer Ansatz ist ThreadPoolExecutor Unterklasse und außer Kraft setzen afterExecute(Runnable, Throwable). Wenn Sie diesen Ansatz folgen sicher sein, rufen execute(Runnable) , anstatt submit(Runnable) oder afterExecute nicht aufgerufen werden.

Per API-Beschreibung:

  

Methode aufgerufen Nach Beendigung der   Ausführung des gegebenen Runnable. Diese   Verfahren wird von dem Thread aufgerufen wird, das   die Aufgabe ausgeführt wird. Wenn nicht-null, die   Throwable ist die abgefangene    RuntimeException oder Error , die verursacht   Ausführung abrupt zu beenden.

     

Hinweis: Bei Aktionen sind eingeschlossen in   Aufgaben (wie FutureTask) entweder   explizit oder durch Methoden wie   einreichen, diese Aufgabe Objekte fangen und   halten Rechen Ausnahmen und   so dass sie nicht abrupt verursachen   Beendigung, und die interne   Ausnahmen sind nicht darauf bestanden   Verfahren .

eine Aufgabe (Callable oder Runnable) vorgelegt werden ThreadPoolExecutors zu einem FuturnTask konvertieren sein, enthält eine Stütze namens callable ist gleich der Aufgabe, die Sie einreichen. FuturnTask hat seine eigene run Verfahren wie folgt. Alle Ausnahme oder throwable in c.call() throwed wird gefangen und in eine Stütze namens outcome gestellt werden. Wenn FuturnTask der get Methode aufrufen, wird outcome throwed werden

FuturnTask.run Von Jdk1.8 Source Code

public void run() {
        ...
        try {
            Callable<V> c = callable;
            if (c != null && state == NEW) {
                V result;
                boolean ran;
                try {
                    result = c.call();
                    ran = true;
                } catch (Throwable ex) {
                    result = null;
                    ran = false;
                    // save ex into `outcome` prop
                    setException(ex);
                }
                if (ran)
                    set(result);
            }
        }
        ...
    }

, wenn Sie die Ausnahme abfangen:

        
      1. skaffman Antwort
        
      2. Überschreiben `afterExecute`, wenn Sie einen ThreadPoolExecutor neu
        @Override
        protected void afterExecute(Runnable r, Throwable t) {
            super.afterExecute(r, t);
            Throwable cause = null;
            if (t == null && r instanceof Future) {
                try {
                    ((Future<?>) r).get();
                } catch (InterruptedException | ExecutionException e) {
                    cause = e;
                }
            } else if (t != null) {
                cause = t;
            }
            if (cause != null) {
                // log error
            }
        }
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top