Wybierz pomiędzy przesłaniem ExecutorService i wykonaniem ExecutorService
Jak wybrać pomiędzy ExecutorService ' S submit lub execute, jeśli zwracana wartość nie jest moją sprawą?
Jeśli przetestuję oba, nie widzę żadnych różnic między tymi dwoma, z wyjątkiem zwracanej wartości.
ExecutorService threadExecutor = Executors.newSingleThreadExecutor();
threadExecutor.execute(new Task());
ExecutorService threadExecutor = Executors.newSingleThreadExecutor();
threadExecutor.submit(new Task());
7 answers
Istnieje różnica dotycząca obsługi wyjątków/błędów.
Zadanie w kolejce z execute()
, które generuje pewne Throwable
spowoduje, że UncaughtExceptionHandler
dla Thread
uruchomione zadanie zostanie wywołane. Domyślna wartość UncaughtExceptionHandler
, która zazwyczaj wypisuje ślad stosu Throwable
do System.err
, zostanie wywołana, jeśli nie został zainstalowany niestandardowy program obsługi.
Z drugiej strony, Throwable
wygenerowane przez zadanie w kolejce do submit()
spowoduje powiązanie Throwable
z Future
, które zostało wytworzone z wywołania do submit()
. Wywołanie get()
na tym Future
rzuci ExecutionException
z oryginalnym Throwable
jako jego przyczyną (dostępnym przez wywołanie getCause()
na ExecutionException
).
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-06-02 21:49:17
wykonaj: użyj go do ognia i zapomnij o połączeniach
submit: użyj go do sprawdzenia wyniku wywołania metody i podjęcia odpowiednich działań na Future
, które zostały zwrócone przez wywołanie
Z javadocs
submit(Callable<T> task)
Przesyła zadanie zwracające wartość do wykonania i zwraca przyszłość reprezentowanie oczekujących wyników zadania.
Future<?> submit(Runnable task)
Przedstawia Runnable zadanie do wykonania i zwraca przyszłość reprezentującą, że zadanie.
void execute(Runnable command)
Wykonuje podaną komendę w pewnym momencie w przyszłości. Polecenie może być wykonywane w nowym wątku, w wątku zbiorczym lub w wątku wywołującym, według uznania implementacji executora.
Należy zachować ostrożność podczas używania submit()
. Ukrywa wyjątek w samym frameworku, chyba że osadzasz kod zadania w bloku try{} catch{}
.
Przykładowy kod: Ten kod połyka Arithmetic exception : / by zero
.
import java.util.concurrent.*;
import java.util.*;
public class ExecuteSubmitDemo{
public ExecuteSubmitDemo()
{
System.out.println("creating service");
ExecutorService service = Executors.newFixedThreadPool(10);
//ExtendedExecutor service = new ExtendedExecutor();
service.submit(new Runnable(){
public void run(){
int a=4, b = 0;
System.out.println("a and b="+a+":"+b);
System.out.println("a/b:"+(a/b));
System.out.println("Thread Name in Runnable after divide by zero:"+Thread.currentThread().getName());
}
});
service.shutdown();
}
public static void main(String args[]){
ExecuteSubmitDemo demo = new ExecuteSubmitDemo();
}
}
Wyjście:
java ExecuteSubmitDemo
creating service
a and b=4:0
Ten sam kod rzuca przez zastąpienie submit()
przez execute
() :
Zastąp
service.submit(new Runnable(){
Z
service.execute(new Runnable(){
Wyjście:
java ExecuteSubmitDemo
creating service
a and b=4:0
Exception in thread "pool-1-thread-1" java.lang.ArithmeticException: / by zero
at ExecuteSubmitDemo$1.run(ExecuteSubmitDemo.java:14)
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)
Jak poradzić sobie z tego typu scenariuszami podczas korzystania z submit()?
- Embed your Task code (albo Runnable lub Callable implementation) with try{} catch{} block code
- implementacja
CustomThreadPoolExecutor
Nowe rozwiązanie:
import java.util.concurrent.*;
import java.util.*;
public class ExecuteSubmitDemo{
public ExecuteSubmitDemo()
{
System.out.println("creating service");
//ExecutorService service = Executors.newFixedThreadPool(10);
ExtendedExecutor service = new ExtendedExecutor();
service.submit(new Runnable(){
public void run(){
int a=4, b = 0;
System.out.println("a and b="+a+":"+b);
System.out.println("a/b:"+(a/b));
System.out.println("Thread Name in Runnable after divide by zero:"+Thread.currentThread().getName());
}
});
service.shutdown();
}
public static void main(String args[]){
ExecuteSubmitDemo demo = new ExecuteSubmitDemo();
}
}
class ExtendedExecutor extends ThreadPoolExecutor {
public ExtendedExecutor() {
super(1,1,60,TimeUnit.SECONDS,new ArrayBlockingQueue<Runnable>(100));
}
// ...
protected void afterExecute(Runnable r, Throwable t) {
super.afterExecute(r, t);
if (t == null && r instanceof Future<?>) {
try {
Object result = ((Future<?>) r).get();
} catch (CancellationException ce) {
t = ce;
} catch (ExecutionException ee) {
t = ee.getCause();
} catch (InterruptedException ie) {
Thread.currentThread().interrupt(); // ignore/reset
}
}
if (t != null)
System.out.println(t);
}
}
Wyjście:
java ExecuteSubmitDemo
creating service
a and b=4:0
java.lang.ArithmeticException: / by zero
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-12-18 03:30:27
Jeśli nie zależy ci na zwracanym typie, użyj execute. to to samo, co submit, tylko bez powrotu przyszłości.
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
2010-10-14 02:09:21
Wzięte z Javadoc:
Metoda
submit
rozszerza metodę bazową {@link Executor#execute
} tworząc i zwracanie {@link Future}, które można wykorzystać do anulowania wykonania i / lub oczekiwania na zakończenie.
Osobiście wolę użycie execute, ponieważ wydaje się to bardziej deklaratywne, chociaż tak naprawdę jest to kwestia osobistych preferencji.
Aby uzyskać więcej informacji: w przypadku implementacji ExecutorService
, podstawowa implementacja jest zwracana przez wywołanie to Executors.newSingleThreadedExecutor()
jest ThreadPoolExecutor
.
Wywołania submit
są dostarczane przez jego rodzica AbstractExecutorService
i wszystkie wywołania wykonują się wewnętrznie. execute jest nadpisywane / dostarczane bezpośrednio przez ThreadPoolExecutor
.
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-05-18 14:34:29
Z Javadoc :
Polecenie może być wykonywane w nowym wątku, w wątku zbiorczym lub w wątku wywołującym, według uznania implementacji executora.
Więc w zależności od implementacji Executor
może się okazać, że zgłaszający wątek blokuje się podczas wykonywania zadania.
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-10-05 18:05:23
[19]} pełna odpowiedź to kompozycja dwóch odpowiedzi, które zostały opublikowane tutaj (plus trochę "ekstra"):
- wysyłając zadanie (a wykonując je) otrzymujesz z powrotem przyszłość, która może zostać użyta do uzyskania wyniku lub anulowania akcji. Nie masz tego rodzaju kontroli, gdy
execute
(ponieważ zwraca identyfikator typuvoid
) -
execute
oczekuje aRunnable
whilesubmit
może przyjmowaćRunnable
lub aCallable
jako argument (więcej informacji na temat różnicy między nimi - zobacz poniżej). -
execute
bąbelki wszystkie niezaznaczone wyjątki od razu (nie może wyrzucić zaznaczonych WYJĄTKÓW!!!submit
wiąże dowolny rodzaj wyjątku od przyszłości, który zwróci się w wyniku, i tylko wtedy, gdy wywołaszfuture.get()
a (zawinięty) wyjątek zostanie wyrzucony . Throwable, który otrzymasz jest instancjąExecutionException
i jeśli nazwiesz ten obiektgetCause()
zwróci oryginalną instancję Throwable.
Jeszcze kilka (powiązanych) punktów:
- nawet jeśli zadanie że chcesz
submit
nie wymaga zwracania wynik, możesz nadal używaćCallable<Void>
(zamiastRunnable
). - Anulowanie zadań można wykonać za pomocą mechanizmuprzerwania . Oto przykład Jak wdrożyć politykę anulowania
Podsumowując, lepiej jest używać {[4] } z Callable
(vs. execute
z Runnable
). A Ja zacytuję "współbieżność Javy w praktyce" Briana Goetza:
6.3.2 wynik-łożysko tasks: Callable and Future
Framework executora używa Runnable jako swojej podstawowej reprezentacji zadań. Runnable jest dość ograniczanie abstrakcji; run nie może zwrócić wartości lub rzut sprawdzony wyjątki, chociaż może mieć skutki uboczne, takie jak zapis do dziennika plik lub umieszczenie wyniku we współdzielonej strukturze danych. Wiele zadań to efektywnie odroczone obliczenia-wykonanie zapytania bazy danych, pobieranie zasób w sieci, czyli obliczanie skomplikowanej funkcji. Na tego typu zadań, Callable jest lepszą abstrakcją: oczekuje że główny punkt wejścia, call, zwróci wartość i przewiduje że może to spowodować wyjątek.7 Executors zawiera kilka narzędzi metody owijania innych typów zadań, w tym Runnable i java.Ochrona./ Align = "left" /
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
2017-05-23 12:10:07
Wystarczy dodać do zaakceptowanej odpowiedzi -
Jednak wyjątki rzucane z zadań sprawiają, że do uncaught obsługa wyjątków tylko dla zadań przesłanych za pomocą execute (); Dla zadań przesłane za pomocą submit () do usługi executor, każdy wyrzucony wyjątek jest uważany za część statusu zwrotu zadania.
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
2019-11-26 13:54:04