Question

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'une plutôt que l'autre?

Était-ce utile?

La solution

Voir l'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   renvoyer un résultat et ne peut pas lancer un   exception cochée.

Autres conseils

  

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

En gros, oui. Consultez les réponses à cette question . Et le javadoc pour Callable<Void> .

  

Quel est le besoin d'avoir les deux si null peut faire tout ce que call() fait?

Parce que <=> l'interface ne peut pas faire tout ce que <=> fait!

<=> existe depuis Java 1.0, mais <=> n'a été introduit que dans Java 1.5 ... pour gérer les cas d'utilisation que <=> ne prend pas en charge. En théorie, l'équipe Java aurait pu modifier la signature de la méthode <=>, mais cela aurait rompu la compatibilité binaire avec le code antérieur à la version 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. C’est l’un des principaux arguments de vente de Java pour l’informatique professionnelle.

Et, bien entendu, il existe des cas d'utilisation dans lesquels une tâche n'a pas besoin de renvoyer un résultat ou de lever une exception vérifiée. Pour ces cas d'utilisation, utiliser <=> est plus concis que d'utiliser <=> et de renvoyer une valeur factice (<=>) à partir de la méthode <=>.

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

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

J'ai trouvé cela dans un autre blog qui peut l'expliquer un peu plus. 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 peut générer des exceptions vérifiées, tandis qu'une <=> instance ne peut pas

Les concepteurs de Java ont ressenti le besoin d'étendre les capacités de l'interface <=>, mais ils ne voulaient pas affecter les utilisations de l'interface <=> et c'est probablement la raison pour laquelle ils ont opté pour un système distinct. interface nommée <=> dans Java 1.5 plutôt que de changer le <>> existant

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 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 fil d’appel ne s’inquiète vraiment pas lorsque vous effectuez votre tâche.

Callable : si vous tentez 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 fil d’appel sera bloqué jusqu’à ce que l’avenir revienne avec des résultats qui attendent la méthode call () de Callable à exécuter.

Pensez donc à une interface avec une classe cible dans laquelle vous avez défini les méthodes encapsulées Runnable et Callable. La classe appelante appellera aléatoirement 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. Ceci est un mécanisme de synchronisation.

Callable l'interface déclare la call() méthode et vous devez fournir les 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;
}
Par contre,

Runnable est une interface qui déclare la run() méthode appelée lorsque vous créez un thread avec le runnable et appelez start (). Vous pouvez également appeler directement run (), mais cela ne fait que d'exécuter la méthode run () et 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:

  1. Un objet <=> ne renvoie pas de résultat alors qu'un <=> objet renvoie un résultat.
  2. Un objet <=> ne peut pas générer une exception vérifiée, alors qu'un objet <=> peut générer une exception.
  3. L'interface <=> existe depuis Java 1.0 alors que <=> n'a été introduit 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é 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 interfaces sont 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);

Objet de ces interfaces de la documentation Oracle:

l'interface Runnable doit être implémentée. 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.

Appelable : A tâche qui renvoie un résultat et peut générer 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. Un ExecutorService, cependant, ne renvoie pas de résultat et ne peut pas lever une exception vérifiée.

Autres différences:

  1. Vous pouvez demander à invokeAny de créer un Discussion . Mais vous ne pouvez pas créer de nouveau sujet en passant invokeAll en tant que paramètre. Vous pouvez transmettre Callable uniquement à run() 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 call() pour déclencher et oublier des appels. Utilisez <=> pour vérifier le résultat.

  3. <=> peut être passé à invokeAll , contrairement à <=>. Les méthodes <=> et <=> exécutent les formes d’exécution en bloc les plus utiles, en exécutant un ensemble de tâches, puis 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 = > <=> pour <=> et <=> pour <=>.

Comme cela a déjà été mentionné ici, Callable est une interface relativement nouvelle et elle a été introduite dans le cadre du package de concurrence. 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.

+-------------------------------------+--------------------------------------------------------------------------------------------------+
|              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 Callable et c'est probablement la raison pour laquelle ils ont opté pour un système distinct. interface nommée <=> dans Java 1.5 plutôt que de modifier l’interface <=> existante faisant partie de Java depuis Java 1.0. source

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 générer une exception vérifiée.
  5. La méthode use () appelable à mettre en file d'attente, mais la méthode runnable à exécuter () à mettre dans la file d'attente.

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

Différence entre Runnable et appelable comme indiqué ci-dessous -

1) La méthode run () de runnable renvoie void , signifie que si vous souhaitez que votre fil renvoie un élément que vous pouvez utiliser ultérieurement, puis vous n'avez pas le choix avec la méthode Runnable run () . Il existe une solution "Callable" : si vous souhaitez renvoyer un élément sous la forme objet , vous devez utiliser Callable au lieu de Runnable . Les interfaces appelables ont la méthode 'call ()' qui renvoie Object .

Signature de la méthode - Runnable - & Gt;

public void run(){}

Appelable - >

public Object call(){}

2) Dans le cas de la méthode Runnable run () , si une exception vérifiée se produit, vous devez traiter avec le bloc catch catch , mais dans le cas d'une Callable call () , méthode que vous pouvez créer une exception vérifiée comme ci-dessous

 public Object call() throws Exception {}

3) Runnable provient de l'ancienne version java 1.0 , mais appelable est disponible dans la version Java 1.5 avec < strong> Cadre d'exécution .

Si vous connaissez les exécuteurs , vous devez utiliser Callable au lieu de Runnable .

J'espère que vous comprenez.

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.

Il est possible de réaliser des multi-threads plus tôt en utilisant l'interface Runnable Depuis 1.0 , mais le problème vient de la fin de la tâche du fil sont incapables de collecter les informations sur les threads. Afin de collecter les données, nous pouvons utiliser des champs statiques.

Exemple Séparez les fils 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 introduit Callable<V> Depuis 1.5 qui renvoie un résultat et peut générer 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 renvoie 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 de la structure 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();
    }
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top