web-dev-qa-db-fra.com

La différence entre les interfaces Runnable et Callable en Java

Quelle est la différence entre l'utilisation des interfaces Runnable et Callable lors de la conception d'un thread simultané en Java, pourquoi choisiriez-vous l'un plutôt que l'autre?

431
Scottm

Voir explication ici .

L'interface Callable est similaire à Runnable, en ce que les deux sont conçus pour les classes dont les instances sont potentiellement exécuté par un autre fil. Un Runnable, cependant, ne le fait pas. renvoyer un résultat et ne peut pas lancer un exception vérifiée.

398
Jorge Ferreira

Quelles sont les différences dans les applications de Runnable et Callable. La différence existe-t-elle uniquement avec le paramètre de retour présent dans Callable?

En gros oui. Voir les réponses à cette question . Et le javadoc pour Callable .

Quel est le besoin d'avoir les deux si Callable peut faire tout ce que Runnable fait?

Parce que l'interface Runnablene peut pas faire tout ce que Callable fait!

Runnable existe depuis Java 1.0, mais Callable n'a été introduit que dans Java 1.5 ... pour gérer les cas d'utilisation que Runnable ne prend pas en charge. En théorie, l'équipe Java aurait pu modifier la signature de la méthode Runnable.run(), mais cela aurait brisé la compatibilité binaire avec le code antérieur à 1.5, nécessitant un recodage lors de la migration de l'ancien code Java vers de nouvelles machines virtuelles. C'est un BIG NO-NO. Java s'efforce d'être compatible avec les versions antérieures ... et c'est l'un des principaux arguments de vente de Java pour l'informatique professionnelle.

Et, évidemment, il existe des cas d'utilisation dans lesquels une tâche ne pas nécessaire ne renvoie ni un résultat ni une exception vérifiée. Pour ces cas d'utilisation, utiliser Runnable est plus concis que d'utiliser Callable<Void> et de renvoyer une valeur factice (null) à partir de la méthode call().

241
Stephen C
  • Une Callable doit implémenter la méthode call() tandis qu'une Runnable doit implémenter la méthode run().
  • Une Callable peut renvoyer une valeur mais une Runnable ne le peut pas.
  • Une Callable peut générer une exception vérifiée, mais une Runnable ne le peut pas.
  • Une Callable peut être utilisée avec les méthodes ExecutorService#invokeXXX(Collection<? extends Callable<T>> tasks) mais une Runnable ne peut pas l'être.

    public interface Runnable {
        void run();
    }
    
    public interface Callable<V> {
        V call() throws Exception;
    }
    
72
nikli

J'ai trouvé cela dans un autre blog qui peut expliquer un peu plus ces différences

Bien que les deux interfaces soient implémentées par les classes qui souhaitent s'exécuter dans un thread d'exécution différent, il existe peu de différences entre les deux interfaces:

  • Une instance Callable<V> renvoie un résultat de type V, contrairement à une instance Runnable.
  • Une instance Callable<V> peut générer des exceptions vérifiées, alors qu'une instance Runnable ne peut pas

Les concepteurs de Java ont ressenti le besoin d'étendre les capacités de l'interface Runnable, mais ils ne voulaient pas affecter les utilisations de l'interface Runnable et c'est probablement la raison pour laquelle ils ont opté pour une interface séparée nommée Callable dans Java 1.5. changer la Runnable déjà existante.

36
amoran

Voyons où on pourrait utiliser Runnable et Callable.

Runnable et Callable s'exécutent sur un autre thread que celui qui appelle. Mais Callable peut renvoyer une valeur et Runnable ne le peut pas. Alors, où cela s'applique-t-il vraiment?.

Runnable : Si vous avez un feu et que vous oubliez une tâche, utilisez Runnable. Placez votre code dans un Runnable et lorsque la méthode run () est appelée, vous pouvez effectuer votre tâche. Le thread appelant ne se soucie vraiment pas lorsque vous effectuez votre tâche.

Callable : Si vous essayez de récupérer une valeur d'une tâche, utilisez Callable. Maintenant appelable seul ne fera pas le travail. Vous aurez besoin d'un avenir que vous entourerez de votre Callable et obtiendrez vos valeurs sur future.get (). Ici, le thread appelant sera bloqué jusqu'à ce que le futur revienne avec des résultats qui attendent à leur tour l'exécution de la méthode call () de Callable.

Pensez donc à une interface vers une classe cible dans laquelle vous avez défini des méthodes encapsulées Runnable et Callable. La classe appelante appellera de manière aléatoire vos méthodes d'interface sans savoir ce qui est Runnable et ce qui est Callable. Les méthodes Runnable s'exécutent de manière asynchrone jusqu'à l'appel d'une méthode Callable. Ici, le thread de la classe appelante va se bloquer puisque vous récupérez des valeurs de votre classe cible. 

REMARQUE: dans votre classe cible, vous pouvez effectuer les appels à Callable et Runnable sur un exécuteur à un seul thread, ce qui rend ce mécanisme similaire à une file d'attente de distribution en série. Donc, tant que l'appelant appelle vos méthodes wrappées Runnable, le thread appelant s'exécutera très rapidement sans blocage. Dès qu'il appelle une méthode Callable encapsulée dans la méthode Future, il devra bloquer jusqu'à ce que tous les autres éléments en file d'attente soient exécutés. Alors seulement, la méthode retournera avec des valeurs. C'est un mécanisme de synchronisation.

26
Kris Subramanian

L'interface Callable déclare la méthode call() et vous devez fournir des génériques car le type d'objet doit être retourné par call () -

public interface Callable<V> {
    /**
     * Computes a result, or throws an exception if unable to do so.
     *
     * @return computed result
     * @throws Exception if unable to compute a result
     */
    V call() throws Exception;
}

Runnable, d'autre part, est une interface qui déclare la méthode run() appelée lorsque vous créez un thread avec le runnable et appelez start (). Vous pouvez aussi appeler directement run () mais cela n'exécute que la méthode run (), c'est le même thread.

public interface Runnable {
    /**
     * When an object implementing interface <code>Runnable</code> is used 
     * to create a thread, starting the thread causes the object's 
     * <code>run</code> method to be called in that separately executing 
     * thread. 
     * <p>
     * The general contract of the method <code>run</code> is that it may 
     * take any action whatsoever.
     *
     * @see     Java.lang.Thread#run()
     */
    public abstract void run();
}

Pour résumer quelques différences notables sont

  1. Un objet Runnable ne renvoie pas de résultat, alors qu'un objet Callable renvoie un résultat.
  2. Un objet Runnable ne peut pas générer une exception vérifiée, alors qu'un objet Callable peut générer une exception
  3. L’interface Runnable existe depuis Java 1.0 alors que Callable n’a été introduite que __.en Java 1.5.

Peu de similitudes incluent

  1. Les instances des classes qui implémentent des interfaces Runnable ou Callable sont potentiellement exécutées par un autre thread.
  2. Les instances des interfaces Callable et Runnable peuvent être exécutées par ExecutorService via la méthode submit ().
  3. Les deux sont des interfaces fonctionnelles et peuvent être utilisées dans les expressions Lambda depuis Java8.

Les méthodes de l'interface ExecutorService sont

<T> Future<T> submit(Callable<T> task);
Future<?> submit(Runnable task);
<T> Future<T> submit(Runnable task, T result);
14
Aniket Thakur

Objet de ces interfaces de la documentation Oracle:

Runnable interface doit être implémenté par toute classe dont les instances sont destinées à être exécutées par un Thread. La classe doit définir une méthode sans argument appelée run.

Callable : Une tâche qui retourne un résultat et peut lever une exception. Les développeurs définissent une seule méthode sans argument appelée call . L'interface Callable est similaire à Runnable, en ce sens que les deux sont conçues pour les classes dont les instances sont potentiellement exécutées par un autre thread. Une Runnable, cependant, ne renvoie pas de résultat et ne peut pas lever une exception contrôlée.

Autres différences:

  1. Vous pouvez passer Runnable pour créer un Thread . Mais vous ne pouvez pas créer de nouveau fil en passant Callable en paramètre. Vous pouvez passer Callable uniquement à ExecutorService instances.

    Exemple:

    public class HelloRunnable implements Runnable {
    
        public void run() {
            System.out.println("Hello from a thread!");
        }   
    
        public static void main(String args[]) {
            (new Thread(new HelloRunnable())).start();
        }
    
    }
    
  2. Utilisez Runnable pour tirer et oublier des appels. Utilisez Callable pour vérifier le résultat.

  3. Callable peut être passé à invokeAll à la différence de Runnable. Les méthodes invokeAny et invokeAll exécutent les formes d’exécution en bloc les plus utiles, en exécutant un ensemble de tâches et en attendant qu’au moins une ou toutes les tâches soient terminées.

  4. Différence triviale: nom de la méthode à implémenter => run() pour Runnable et call() pour Callable.

14
Ravindra babu

Comme cela a déjà été mentionné ici, Callable est une interface relativement nouvelle et a été introduite dans le cadre du package de simultanéité. Callable et Runnable peuvent être utilisés avec les exécuteurs. La classe Thread (qui implémente Runnable elle-même) ne prend en charge que Runnable.

Vous pouvez toujours utiliser Runnable avec des exécuteurs. L'avantage de Callable est que vous pouvez l'envoyer à l'exécuteur et récupérer immédiatement le résultat futur qui sera mis à jour à la fin de l'exécution. La même chose peut être implémentée avec Runnable, mais dans ce cas, vous devez gérer vous-même les résultats. Par exemple, vous pouvez créer une file d'attente des résultats qui contiendra tous les résultats. D'autres threads peuvent attendre dans cette file d'attente et gérer les résultats qui arrivent.

10
AlexR
+-------------------------------------+--------------------------------------------------------------------------------------------------+
|              Runnable               |                                           Callable<T>                                            |
+-------------------------------------+--------------------------------------------------------------------------------------------------+
| Introduced in Java 1.0 of Java.lang | Introduced in Java 1.5 of Java.util.concurrent library                                           |
| Runnable cannot be parametrized     | Callable is a parametrized type whose type parameter indicates the return type of its run method |
| Runnable has run() method           | Callable has call() method                                                                       |
| Runnable.run() returns void         | Callable.call() returns a value of Type T                                                        |
| Can not throw Checked Exceptions    | Can throw Checked Exceptions                                                                     |
+-------------------------------------+--------------------------------------------------------------------------------------------------+

Les concepteurs de Java ont ressenti le besoin d'étendre les capacités de l'interface Runnable, mais ils ne voulaient pas affecter les utilisations de l'interface Runnable et c'est probablement la raison pour laquelle ils ont opté pour une interface séparée nommée Callable en Java 1.5 changer l'interface Runnable déjà existante qui fait partie de Java depuis Java 1.0. la source

5
Premraj

Les différences entre Callable et Runnable sont les suivantes:

  1. Callable est introduit dans JDK 5.0 mais Runnable est introduit dans JDK 1.0.
  2. Callable a la méthode call () mais Runnable a la méthode run ().
  3. Callable a une méthode call qui retourne une valeur, mais Runnable a une méthode run qui ne renvoie aucune valeur.
  4. la méthode call peut générer une exception vérifiée, mais la méthode run ne peut pas déclencher une exception vérifiée.
  5. Appelable utilise la méthode submit () à mettre en file d'attente des tâches, mais Runnable utilise la méthode execute () à mettre en file d'attente.
3
Raman Gupta

Callable et Runnable les deux sont similaires et peuvent être utilisés pour l'implémentation de thread. Si vous implémentez Runnable, vous devez implémenter la méthode run () mais, dans le cas de callable, vous devez implémenter la méthode call (). Les deux méthodes fonctionnent de manière similaire, mais callable call. () ont plus de flexibilité. Il existe quelques différences entre elles. 

Différence entre Runnable et callable comme ci-dessous-- 

1) La méthode run () de runnable renvoie void, cela signifie que si vous voulez que votre thread retourne quelque chose que vous pouvez utiliser, vous avez le choix no avec Runnable run () méthode. Il existe une solution 'Callable'. Si vous voulez renvoyer quelque chose sous la forme object, vous devriez alors utiliser Callable au lieu de Runnable. Les interfaces appelables ont la méthode 'call ()' qui renvoie Object.

Méthode signature - Runnable-> 

public void run(){}

Callable-> 

public Object call(){}

2) Dans le cas de la méthode Runnable run () si une exception vérifiée survient, vous devez avoir à gérer avec try catch block, mais dans le cas de la méthode Callable call (), vous peut lancer une exception vérifiée comme ci-dessous 

 public Object call() throws Exception {}

3) Runnable provient de l'ancienne version Java 1.0, mais callable est venu dans la version Java 1.5 avec le framework Executer.

Si vous connaissez Executers, vous devriez utiliser Callable au lieu de Runnable.

J'espère que tu as compris.

0
Sudhakar Pandey

Runnable (vs) Callable entre en jeu lorsque nous utilisons le framework Executer.

ExecutorService est une sous-interface de Executor , qui accepte les tâches exécutables et appelables.

Le multi-threading précédent peut être réalisé en utilisant InterfaceRunnable_ {Depuis 1.0, mais dans ce cas, le problème est que, une fois la tâche du fil terminée, nous ne pouvons pas collecter les informations sur les threads. Afin de collecter les données, nous pouvons utiliser des champs statiques.

Exemple Séparez les discussions pour collecter les données de chaque élève.

static HashMap<String, List> multiTasksData = new HashMap();
public static void main(String[] args) {
    Thread t1 = new Thread( new RunnableImpl(1), "T1" );
    Thread t2 = new Thread( new RunnableImpl(2), "T2" );
    Thread t3 = new Thread( new RunnableImpl(3), "T3" );

    multiTasksData.put("T1", new ArrayList() ); // later get the value and update it.
    multiTasksData.put("T2", new ArrayList() );
    multiTasksData.put("T3", new ArrayList() );
}

Pour résoudre ce problème, ils ont introduitCallable<V>_ {Depuis 1.5 qui retourne un résultat et peut lever une exception.

  • Méthode abstraite unique : les interfaces Callable et Runnable ont une seule méthode abstraite, ce qui signifie qu'elles peuvent être utilisées dans les expressions lambda dans Java 8.

    public interface Runnable {
    public void run();
    }
    
    public interface Callable<Object> {
        public Object call() throws Exception;
    }
    

Il existe différentes manières de déléguer des tâches d'exécution à un ExecutorService .

  • execute(Runnable task):void crée un nouveau thread mais ne bloque pas le thread principal ou le thread appelant car cette méthode retourne void.
  • submit(Callable<?>):Future<?>, submit(Runnable):Future<?> crée un nouveau thread et bloque le thread principal lorsque vous utilisez future.get () .

Exemple d'utilisation d'interfaces Runnable, Callable with Executor.

class CallableTask implements Callable<Integer> {
    private int num = 0;
    public CallableTask(int num) {
        this.num = num;
    }
    @Override
    public Integer call() throws Exception {
        String threadName = Thread.currentThread().getName();
        System.out.println(threadName + " : Started Task...");

        for (int i = 0; i < 5; i++) {
            System.out.println(i + " : " + threadName + " : " + num);
            num = num + i;
            MainThread_Wait_TillWorkerThreadsComplete.sleep(1);
        }
        System.out.println(threadName + " : Completed Task. Final Value : "+ num);

        return num;
    }
}
class RunnableTask implements Runnable {
    private int num = 0;
    public RunnableTask(int num) {
        this.num = num;
    }
    @Override
    public void run() {
        String threadName = Thread.currentThread().getName();
        System.out.println(threadName + " : Started Task...");

        for (int i = 0; i < 5; i++) {
            System.out.println(i + " : " + threadName + " : " + num);
            num = num + i;
            MainThread_Wait_TillWorkerThreadsComplete.sleep(1);
        }
        System.out.println(threadName + " : Completed Task. Final Value : "+ num);
    }
}
public class MainThread_Wait_TillWorkerThreadsComplete {
    public static void main(String[] args) throws InterruptedException, ExecutionException {
        System.out.println("Main Thread start...");
        Instant start = Java.time.Instant.now();

        runnableThreads();
        callableThreads();

        Instant end = Java.time.Instant.now();
        Duration between = Java.time.Duration.between(start, end);
        System.out.format("Time taken : %02d:%02d.%04d \n", between.toMinutes(), between.getSeconds(), between.toMillis()); 

        System.out.println("Main Thread completed...");
    }
    public static void runnableThreads() throws InterruptedException, ExecutionException {
        ExecutorService executor = Executors.newFixedThreadPool(4);
        Future<?> f1 = executor.submit( new RunnableTask(5) );
        Future<?> f2 = executor.submit( new RunnableTask(2) );
        Future<?> f3 = executor.submit( new RunnableTask(1) );

        // Waits until pool-thread complete, return null upon successful completion.
        System.out.println("F1 : "+ f1.get());
        System.out.println("F2 : "+ f2.get());
        System.out.println("F3 : "+ f3.get());

        executor.shutdown();
    }
    public static void callableThreads() throws InterruptedException, ExecutionException {
        ExecutorService executor = Executors.newFixedThreadPool(4);
        Future<Integer> f1 = executor.submit( new CallableTask(5) );
        Future<Integer> f2 = executor.submit( new CallableTask(2) );
        Future<Integer> f3 = executor.submit( new CallableTask(1) );

        // Waits until pool-thread complete, returns the result.
        System.out.println("F1 : "+ f1.get());
        System.out.println("F2 : "+ f2.get());
        System.out.println("F3 : "+ f3.get());

        executor.shutdown();
    }
}
0
Yash