Wie man richtig Runtime von Testamentsvollstrecker fangen?
-
18-09-2019 - |
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 uncaughtExceptionHandler
s für die Thread
s 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?
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
oderError
, 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
}
}