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?
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.
Quelles sont les différences dans les applications de
Runnable
etCallable
. La différence existe-t-elle uniquement avec le paramètre de retour présent dansCallable
?
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 queRunnable
fait?
Parce que l'interface Runnable
ne 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()
.
Callable
doit implémenter la méthode call()
tandis qu'une Runnable
doit implémenter la méthode run()
.Callable
peut renvoyer une valeur mais une Runnable
ne le peut pas.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;
}
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:
Callable<V>
renvoie un résultat de type V
, contrairement à une instance Runnable
.Callable<V>
peut générer des exceptions vérifiées, alors qu'une instance Runnable
ne peut pasLes 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.
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.
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
Runnable
ne renvoie pas de résultat, alors qu'un objet Callable
renvoie un résultat.Runnable
ne peut pas générer une exception vérifiée, alors qu'un objet Callable
peut générer une exception Runnable
existe depuis Java 1.0 alors que Callable
n’a été introduite que __.en Java 1.5.Peu de similitudes incluent
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:
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:
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.
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();
}
}
Utilisez Runnable
pour tirer et oublier des appels. Utilisez Callable
pour vérifier le résultat.
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.
Différence triviale: nom de la méthode à implémenter => run()
pour Runnable
et call()
pour Callable
.
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.
+-------------------------------------+--------------------------------------------------------------------------------------------------+
| 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
Les différences entre Callable et Runnable sont les suivantes:
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.
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();
}
}