web-dev-qa-db-ger.com

Was ist der Unterschied zwischen ExecutorService.submit und ExecutorService.execute in diesem Code in Java?

Ich lerne, ExectorService zu verwenden, um threads zu bündeln und Aufgaben zu versenden. Ich habe unten ein einfaches Programm

import Java.util.concurrent.ExecutorService;
import Java.util.concurrent.Executors;
import Java.util.concurrent.TimeUnit;


class Processor implements Runnable {

    private int id;

    public Processor(int id) {
        this.id = id;
    }

    public void run() {
        System.out.println("Starting: " + id);

        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            System.out.println("sorry, being interupted, good bye!");
            System.out.println("Interrupted "+Thread.currentThread().getName());
            e.printStackTrace();    
        }

        System.out.println("Completed: " + id);
    }
}


public class ExecutorExample {

    public static void main(String[] args) {
        Boolean isCompleted=false;

        ExecutorService executor = Executors.newFixedThreadPool(2);

        for(int i=0; i<5; i++) {
            executor.execute(new Processor(i));
        }

        //executor does not accept any more tasks but the submitted tasks continue
        executor.shutdown();

        System.out.println("All tasks submitted.");

        try {
            //wait for the exectutor to terminate normally, which will return true
            //if timeout happens, returns false, but this does NOT interrupt the threads
            isCompleted=executor.awaitTermination(100, TimeUnit.SECONDS);
            //this will interrupt thread it manages. catch the interrupted exception in the threads 
            //If not, threads will run forever and executor will never be able to shutdown.
            executor.shutdownNow();
        } catch (InterruptedException e) {
        }

        if (isCompleted){
        System.out.println("All tasks completed.");
       }
        else {
            System.out.println("Timeout "+Thread.currentThread().getName());
        }
    }
        }

Es ist nichts Besonderes, erstellt jedoch zwei threads und übermittelt insgesamt 5 Aufgaben. Nachdem jeder thread seine Aufgabe abgeschlossen hat, wird der nächste, Verwendet. Im obigen Code verwende ich executor.submit. Ich habe auch zu executor.execute gewechselt. Ich sehe aber keinen Unterschied in der Ausgabe. Inwiefern unterscheiden sich die submit and execute-Methoden? Das sagt die API

Die Methode submit erweitert die Basismethode Executor.execute (Java.lang.Runnable), indem eine Future erstellt und zurückgegeben wird, mit der die Ausführung abgebrochen und/oder auf den Abschluss gewartet werden kann. Die Methoden invokeAny und invokeAll führen die gebräuchlichsten Formen der Massenausführung aus, führen eine Auflistung von Aufgaben durch und warten, bis mindestens eine oder alle Aufgaben abgeschlossen sind. (Mit der Klasse ExecutorCompletionService können benutzerdefinierte Varianten dieser Methoden geschrieben werden.)

Aber es ist mir nicht klar, was es genau bedeutet?

34
brain storm

Wie Sie aus dem JavaDoc sehen, gibt execute(Runnable) nichts zurück.

submit(Callable<T>) gibt jedoch ein Future-Objekt zurück, mit dem Sie den laufenden Thread später programmatisch abbrechen und die T abrufen können, die zurückgegeben wird, wenn die Callable abgeschlossen ist. Siehe JavaDoc of Future für weitere Details

Future<?> future = executor.submit(longRunningJob);
...
//long running job is taking too long
future.cancel(true);

Wenn Wenn future.get() == null und keine Ausnahme auslöst, wurde Runnable erfolgreich ausgeführt

38
dkatzel

Der Unterschied ist, dass execute einfach die Task ohne weiteres startet, während submit ein Future-Objekt zur Verwaltung der Task zurückgibt. Mit dem Objekt Future können Sie Folgendes tun:

  • Brechen Sie die Aufgabe mit der Methode cancel vorzeitig ab.
  • Warten Sie mit get, bis die Task abgeschlossen ist.

Die Future-Schnittstelle ist nützlicher, wenn Sie eine Callable an den Pool übergeben. Der Rückgabewert der call-Methode wird zurückgegeben, wenn Sie Future.get aufrufen. Wenn Sie keinen Verweis auf die Future pflegen, besteht kein Unterschied.

40
tbodt

execute: Verwenden Sie es für Feuer und vergessen Sie Anrufe

submit: Verwenden Sie diese Option, um das Ergebnis des Methodenaufrufs zu überprüfen und geeignete Maßnahmen für Future zu ergreifen, die vom Aufruf zurückgegeben wurden

Hauptunterschied: Exception Handhabung

submit() verbirgt nicht behandelte Exception im Framework selbst.

execute() wirft Exception nicht behandelt.

Lösung für die Behandlung von Ausnahmen mit submit()

  1. Wickeln Sie Ihren Callable or Runnable code in try{} catch{} block

    ODER 

  2. Behalte future.get() call in try{} catch{} block

    ODER 

  3. eigene ThreadPoolExecutor implementieren und afterExecute-Methode überschreiben

Bezüglich Tour andere Fragen an

invokeAll :

Führt die angegebenen Aufgaben aus und gibt eine Liste der Futures zurück, die ihren Status und ihre Ergebnisse behalten, wenn alle abgeschlossen sind oder das Timeout abgelaufen ist, je nachdem, was zuerst eintritt.

invokeAny :

Führt die angegebenen Aufgaben aus und gibt das Ergebnis einer erfolgreich abgeschlossenen Task zurück (d. H. Ohne eine Ausnahme auszulösen), wenn dies vor Ablauf der angegebenen Zeitüberschreitung erledigt ist.

Verwenden Sie invokeAll, wenn Sie warten möchten, bis alle übergebenen Aufgaben abgeschlossen sind.

Verwenden Sie invokeAny, wenn Sie eine Aufgabe aus N übergebenen Aufgaben erfolgreich abschließen möchten. In diesem Fall werden laufende Aufgaben abgebrochen, wenn eine der Aufgaben erfolgreich abgeschlossen wurde. 

Zugehöriger Beitrag mit Code-Beispiel:

Wählen Sie zwischen dem ExecutorService-Senden und dem ExecutorService-Ausführen

12
Ravindra babu

Senden - Gibt ein Future-Objekt zurück, mit dem das Ergebnis der übergebenen Aufgabe überprüft werden kann. Kann zum Abbrechen oder zum Überprüfen von isDone usw. verwendet werden. 

Ausführen - gibt nichts zurück. 

5
Preetham R U

Ein Hauptunterschied zwischen der Methode submit () und der Methode execute () besteht darin, dass ExecuterService.submit () das Ergebnis der Berechnung zurückgeben kann, da es einen Rückgabetyp von Future gibt. Die Methode Ausführen () kann jedoch nichts zurückgeben, da der Rückgabetyp ungültig ist. Die Kernschnittstelle im Executor-Framework von Java 1.5 ist die Executor-Schnittstelle, die die Ausführungsmethode (Runnable Task) definiert, deren Hauptzweck es ist, die Task von ihrer Ausführung zu trennen.

Jede an Executor übergebene Aufgabe kann von demselben Thread, einem Arbeitsthread aus einem Threadpool oder einem anderen Thread ausgeführt werden.

Auf der anderen Seite ist die submit () -Methode in der ExecutorService-Schnittstelle definiert, die eine Unterschnittstelle von Executor ist und die Funktionalität zum Beenden des Thread-Pools sowie das Hinzufügen der submit () - Methode hinzufügt, die eine Callable-Task annehmen und ein Ergebnis zurückgeben kann der Berechnung.

Ähnlichkeiten zwischen dem Ausführen () und Senden () sowie:

  1. Sowohl die submit () - als auch die execute () -Methode werden verwendet, um eine Aufgabe an das Executor-Framework zur asynchronen Ausführung zu übergeben.
  2. Sowohl submit () als auch execute () können eine ausführbare Aufgabe akzeptieren.
  3. Sie können von der ExecutorService-Schnittstelle aus auf submit () und execute () zugreifen, da dadurch auch die Executor-Schnittstelle erweitert wird, die die Methode execute () deklariert.

Abgesehen von der Tatsache, dass die submit () -Methode die Ausgabe zurückgeben kann und execute () nicht kann, werden im Folgenden weitere Unterschiede zwischen diesen beiden Schlüsselmethoden des Executor-Frameworks von Java 5 aufgeführt.

  1. Das submit () kann sowohl die ausführbare als auch die aufrufbare Task annehmen, aber execute () kann nur die ausführbare Task akzeptieren.
  2. Die submit () -Methode wird in der ExecutorService-Schnittstelle deklariert, während die execute () -Methode in der Executor-Schnittstelle deklariert wird.
  3. Der Rückgabetyp der submit () -Methode ist ein Future-Objekt, der Rückgabetyp der execute () -Methode ist jedoch ungültig.
2
amitkumar12788

Wenn Sie den Quellcode überprüfen, werden Sie feststellen, dass submit eine Art Wrapper für execute ist.

public Future<?> submit(Runnable task) {
    if (task == null) throw new NullPointerException();
    RunnableFuture<Void> ftask = newTaskFor(task, null);
    execute(ftask);
    return ftask;
}
1
Koray Tugay

grundsätzlich werden beide Aufrufe ausgeführt, wenn Sie ein zukünftiges Objekt wünschen, rufen Sie die submit () -Methode .__ auf. hier vom doc

public <T> Future<T> submit(Callable<T> task) {
    if (task == null) throw new NullPointerException();
    RunnableFuture<T> ftask = newTaskFor(task);
    execute(ftask);
    return ftask;
}


public <T> Future<T> submit(Runnable task, T result) {
    if (task == null) throw new NullPointerException();
    RunnableFuture<T> ftask = newTaskFor(task, result);
    execute(ftask);
    return ftask;
}

wie Sie sehen, hat Java wirklich keine Möglichkeit, einen anderen Thread als den Aufruf der run () - Methode IMO zu starten. da ich auch festgestellt habe, dass die Callable.call()-Methode innerhalb der run()-Methode aufgerufen wird. Wenn das Objekt also aufrufbar ist, würde es noch die run()-Methode aufrufen, die inturn die call()-Methode von doc aus aufrufen würde.

public void run() {
    if (state != NEW ||
        !UNSAFE.compareAndSwapObject(this, runnerOffset,
                                     null, Thread.currentThread()))
        return;
    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;
                setException(ex);
            }
            if (ran)
                set(result);
        }
    } finally {
        // runner must be non-null until state is settled to
        // prevent concurrent calls to run()
        runner = null;
        // state must be re-read after nulling runner to prevent
        // leaked interrupts
        int s = state;
        if (s >= INTERRUPTING)
            handlePossibleCancellationInterrupt(s);
    }
}
0
amarnath harish