116 votes

Quelle est la différence entre ExecutorService.submit et ExecutorService.execute dans ce code en Java ?

J'apprends à utiliser ExectorService à la piscine threads et envoyer des tâches. J'ai un programme simple ci-dessous

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());
        }
    }
}

Il ne fait rien d'extraordinaire, mais crée deux threads et soumet 5 tâches au total. Après chaque thread termine sa tâche, il prend la suivante, Dans le code ci-dessus, j'utilise executor.submit . J'ai également changé pour executor.execute . Mais je ne vois aucune différence dans la sortie. De quelle manière les submit y execute méthodes différentes ? Voici ce que le API dit

La méthode submit étend la méthode de base Executor.execute(java.lang.Runnable) en créant et en renvoyant un Future qui peut être utilisé pour annuler l'exécution et/ou attendre l'achèvement. Les méthodes invokeAny et invokeAll exécutent les formes les plus courantes d'exécution en masse, en exécutant un ensemble de tâches et en attendant qu'au moins l'une d'entre elles, voire toutes, se termine. (La classe ExecutorCompletionService peut être utilisée pour écrire des variantes personnalisées de ces méthodes).

Mais je ne comprends pas bien ce que cela signifie exactement ?

92voto

dkatzel Points 9062

Comme vous le voyez dans la JavaDoc execute(Runnable) ne renvoie rien.

Cependant, submit(Callable<T>) renvoie un Future ce qui vous permet de programmer l'annulation du fil d'exécution plus tard et d'obtenir l'objet T qui est renvoyée lorsque l Callable complète. Voir JavaDoc du futur pour plus de détails

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

D'ailleurs, si future.get() == null et ne lève pas d'exception, alors la Runnable s'est exécutée avec succès.

59voto

tbodt Points 6671

La différence est que execute lance simplement la tâche sans autre forme de procès, alors que submit renvoie un Future pour gérer la tâche. Vous pouvez faire les choses suivantes avec l'objet Future objet :

  • Annuler la tâche prématurément, avec l'option cancel méthode.
  • Attendez que la tâche finisse de s'exécuter, avec get .

En Future est plus utile si vous soumettez un Callable à la piscine. La valeur de retour de la fonction call sera retournée lorsque vous appellerez Future.get . Si vous ne maintenez pas une référence à l'élément Future il n'y a pas de différence.

39voto

Ravindra babu Points 5571

execute: Utilisez-le pour les appels d'incendie et d'oubli

submit: Utilisez-le pour inspecter le résultat de l'appel d'une méthode et prendre les mesures appropriées en cas d'échec. Future retourné par l'appel

Différence majeure : Exception manipulation

submit() cache les personnes non manipulées Exception dans le cadre même.

execute() lance un appel non maîtrisé Exception .

Solution pour le traitement des exceptions avec submit()

  1. Enveloppez votre Callable or Runnable code in try{} catch{} block

    OU

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

    OU

  3. mettre en œuvre votre propre ThreadPoolExecutor et de passer outre afterExecute méthode

En ce qui concerne les autres questions sur la tournée

invokeAll :

Exécute les tâches données, en retournant une liste de Futures contenant leur état et leurs résultats lorsque toutes les tâches sont terminées ou lorsque le délai d'attente expire, selon ce qui se produit en premier.

invokeAny :

Exécute les tâches données, en renvoyant le résultat de celle qui s'est achevée avec succès (c'est-à-dire sans lever d'exception), le cas échéant, avant l'expiration du délai donné.

Utilice invokeAll si vous voulez attendre que toutes les tâches soumises soient terminées.

Utilice invokeAny si vous cherchez à mener à bien une tâche parmi les N tâches soumises. Dans ce cas, les tâches en cours seront annulées si l'une des tâches se termine avec succès.

Related post with code example :

Choisir entre le submit de ExecutorService et le execute de ExecutorService

10voto

amitkumar12788 Points 767

La principale différence entre les méthodes submit() et execute() est que la méthode ExecuterService.submit()peut renvoyer le résultat du calcul car son type de retour est Future, mais la méthode execute() ne peut rien renvoyer car son type de retour est void. L'interface centrale du cadre Executor de Java 1.5 est l'interface Executor qui définit la méthode execute(Runnable task), dont le but principal est de séparer la tâche de son exécution.

Toute tâche soumise à l'Executor peut être exécutée par le même thread, par un worker thread d'un pool de threads ou par tout autre thread.

D'autre part, la méthode submit() est définie dans l'interface ExecutorService qui est une sous-interface d'Executor et ajoute la fonctionnalité de terminer le pool de threads, ainsi que l'ajout de la méthode submit() qui peut accepter une tâche appelable et renvoyer un résultat de calcul.

Similitudes entre les fonctions execute() et submit() également :

  1. Les méthodes submit() et execute() sont utilisées pour soumettre une tâche au cadre Executor pour une exécution asynchrone.
  2. Les fonctions submit() et execute() peuvent toutes deux accepter une tâche Runnable.
  3. Vous pouvez accéder à submit() et execute() à partir de l'interface ExecutorService car elle étend également l'interface Executor qui déclare la méthode execute().

Outre le fait que la méthode submit() peut renvoyer une sortie et que la méthode execute() ne le peut pas, voici d'autres différences notables entre ces deux méthodes clés du cadre Executor de Java 5.

  1. La fonction submit() peut accepter les deux types de tâches, Runnable et Callable, mais la fonction execute() ne peut accepter que les tâches Runnable.
  2. La méthode submit() est déclarée dans l'interface ExecutorService tandis que la méthode execute() est déclarée dans l'interface Executor.
  3. Le type de retour de la méthode submit() est un objet Future mais le type de retour de la méthode execute() est void.

8voto

Koray Tugay Points 1885

Si vous vérifiez le code source, vous verrez que submit est une sorte d'enveloppe pour execute

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X