Jak wybrać pomiędzy przesłaniem lub wykonaniem przez ExecutorService , jeśli zwracana wartość nie jest moim przedmiotem?
Jeśli przetestuję oba, nie zauważyłem żadnych różnic między nimi oprócz zwróconej wartości.
ExecutorService threadExecutor = Executors.newSingleThreadExecutor();
threadExecutor.execute(new Task());
ExecutorService threadExecutor = Executors.newSingleThreadExecutor();
threadExecutor.submit(new Task());
źródło
Runnable
otoczenie jest owinięte,Task
czy też nie, nad którym możesz nie mieć kontroli. Na przykład, jeśli twojeExecutor
jest w rzeczywistościScheduledExecutorService
, twoje zadanie zostanie wewnętrznie owinięte,Future
a nieprzechwyconeThrowable
s zostaną powiązane z tym obiektem.Future
Oczywiście mam na myśli „zawinięty w lub nie”. Zobacz na przykład Javadoc dla ScheduledThreadPoolExecutor # execute .wykonaj : Użyj go do strzelania i zapominania połączeń
Prześlij : użyj go, aby sprawdzić wynik wywołania metody i podjąć odpowiednie działania w przypadku
Future
sprzeciwu zwróconego przez wywołanieZ javadocs
submit(Callable<T> task)
Future<?> submit(Runnable task)
Podczas używania należy zachować ostrożność
submit()
. Ukrywa wyjątek w samej strukturze, chyba że kod zadania zostanie osadzony wtry{} catch{}
bloku.Przykładowy kod: ten kod połyka
Arithmetic exception : / by zero
.wynik:
Ten sam kod rzuca zastępując
submit()
zexecute
():Zastąpić
z
wynik:
Jak obsłużyć tego typu scenariusze podczas korzystania z funkcji Submit ()?
CustomThreadPoolExecutor
Nowe rozwiązanie:
wynik:
źródło
jeśli nie zależy ci na typie zwrotu, użyj execute. to to samo, co prześlij, tylko bez powrotu Future.
źródło
Zaczerpnięte z Javadoc:
Osobiście wolę użycie execute, ponieważ wydaje się bardziej deklaratywne, chociaż tak naprawdę jest to kwestia osobistych preferencji.
Aby podać więcej informacji: w przypadku
ExecutorService
implementacji podstawową implementacją zwracaną przez wywołanieExecutors.newSingleThreadedExecutor()
jestThreadPoolExecutor
.Te
submit
połączenia są dostarczane przez jego rodzicaAbstractExecutorService
i wszystkie połączenia wykonać wewnętrznie. Wykonaj jest nadpisane / dostarczone przezThreadPoolExecutor
bezpośrednio.źródło
Z Javadoc :
Więc w zależności od wdrożenia
Executor
może się okazać, że wątek wysyłający blokuje się podczas wykonywania zadania.źródło
Pełna odpowiedź jest kompozycją dwóch odpowiedzi, które zostały tutaj opublikowane (plus trochę „dodatkowych”):
execute
(ponieważ jest to identyfikator typu zwracanegovoid
)execute
oczekuje, że jakiśRunnable
czassubmit
może potrwać jako argument aRunnable
lub aCallable
(więcej informacji na temat różnicy między nimi - patrz poniżej).execute
wywołuje wszystkie odznaczone wyjątki od razu (nie może generować sprawdzonych wyjątków !!!), jednocześniesubmit
wiążąc każdy rodzaj wyjątku z przyszłością, która powróci w wyniku, i tylko wtedy, gdy wywołaszfuture.get()
(zawinięty) wyjątek zostanie zgłoszony. Thralble, który dostaniesz, jest instancją,ExecutionException
a jeśli nazwiesz ten obiekt,getCause()
zwróci oryginalny Throwable.Kilka innych (powiązanych) punktów:
submit
, nie wymaga zwrócenia wyniku, nadal możesz go użyćCallable<Void>
(zamiast używaćRunnable
).Podsumowując, lepszą praktyką jest używanie
submit
zCallable
(w porównaniuexecute
z aRunnable
). Cytuję z „Współbieżności Java w praktyce” Briana Goetza:źródło
Po prostu dodając do zaakceptowanej odpowiedzi
Źródło
źródło