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());
Author: Ravindra babu, 2010-10-14

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).

 205
Author: hochraldo,
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()?

  1. Embed your Task code (albo Runnable lub Callable implementation) with try{} catch{} block code
  2. 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
 61
Author: Ravindra babu,
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.

 11
Author: Steven,
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.

 7
Author: Syntax,
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.

 2
Author: rxg,
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 typu void)
  • execute oczekuje a Runnable while submit może przyjmować Runnable lub a Callable 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!!!submitwiąże dowolny rodzaj wyjątku od przyszłości, który zwróci się w wyniku, i tylko wtedy, gdy wywołasz future.get() a (zawinięty) wyjątek zostanie wyrzucony . Throwable, który otrzymasz jest instancją ExecutionException i jeśli nazwiesz ten obiekt getCause() 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> (zamiast Runnable).
  • 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" /

 1
Author: Nir Alfasi,
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.

Źródło

 1
Author: abhihello123,
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