Jak prawidłowo złapać RuntimeExceptions od wykonawców?
Powiedz, że mam następujący kod:
ExecutorService executor = Executors.newSingleThreadExecutor();
executor.execute(myRunnable);
Teraz, jeśli myRunnable
rzuca RuntimeExcpetion
, Jak mogę go złapać? Jednym ze sposobów byłoby dostarczenie własnej implementacji ThreadFactory
do newSingleThreadExecutor()
i ustawienie niestandardowych uncaughtExceptionHandler
s dla Thread
s, które z niej pochodzą. Innym sposobem byłoby zawinięcie myRunnable
do lokalnego (anonimowego) Runnable
zawierającego try-catch-block. Może są też inne podobne obejścia. Ale... jakoś to jest brudne, czuję, że nie powinno być tak skomplikowane. Czy istnieje czyste rozwiązanie?
5 answers
Czyste obejście polega na użyciu ExecutorService.submit()
zamiast execute()
. Zwraca Future
, którego można użyć do pobrania wyniku lub wyjątku zadania:
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();
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-11-06 14:53:36
Udekoruj runnable w innym runnable, który łapie wyjątki runtime i obsługuje je:
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));
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-11-06 15:02:35
Dlaczego nie zadzwonić ExecutorService#submit()
, get the Future
wstecz, a następnie samodzielnie obsługiwać ewentualne wyjątki podczas wywoływania Future#get()
?
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-03-07 18:44:49
Skaffman ma rację, ponieważ użycie submit
jest najczystszym podejściem. Alternatywnym podejściem jest podklasa ThreadPoolExecutor
i nadpisać afterExecute(Runnable, Throwable)
. Jeśli zastosujesz to podejście pamiętaj, aby zadzwonić execute(Runnable)
zamiast submit(Runnable)
lub afterExecute
nie będą wywoływane.
Zgodnie z opisem API:
Metoda wywołana po zakończeniu wykonanie danego Runnable. To metoda jest wywoływana przez wątek, który wykonałem zadanie. If non-null, the Throwable is the uncaught
RuntimeException
lubError
to spowodowało egzekucja w celu natychmiastowego zakończenia.Uwaga: Gdy działania są zamknięte w zadania (np. FutureTask) albo jawnie lub za pomocą metod takich jak złożyć, te obiekty zadania złapać i utrzymanie WYJĄTKÓW obliczeniowych oraz więc nie powodują nagłego wypowiedzenie, a wewnętrzne wyjątki są nie przekazywane do tego metoda .
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-11-06 15:04:19
Zadanie (Callable
lub Runnable
) złożone do ThreadPoolExecutors
zostanie przekonwertowane na FuturnTask
, zawiera prop o nazwie callable
równa się zadaniu, które przesyłasz. FuturnTask ma własną metodę run
w następujący sposób. Wszystkie wyjątki lub przedmioty rzucane w c.call()
zostaną przechwycone i umieszczone w rekwizytorze o nazwie outcome
. Podczas wywoływania metody FuturnTask get
, outcome
zostanie wyrzucona
FuturnTask.Uruchom z kodu źródłowego Jdk1. 8
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);
}
}
...
}
Jeśli chcesz złapać wyjątek:
- 1. skaffman ' s odpowiedź
- 2. zastąp "afterExecute", gdy nowy ThreadPoolExecutor
@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
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-08-25 11:49:00