Java Callable et Future sont largement utilisés en programmation multithread. Dans les derniers messages, nous avons beaucoup appris sur les threads Java, mais parfois nous souhaitons qu’un thread puisse renvoyer une valeur que nous pouvons utiliser. Java 5 a introduit l’interface java.util.concurrent.Callable dans le package de concurrence, qui est similaire à l’interface Runnable mais qui peut renvoyer n’importe quel objet et être capable de lever une exception.
Java Callable
L’interface Java Callable utilise Generics pour définir le type de retour de l’objet. La classe Executors fournit des méthodes utiles pour exécuter Java Callable dans un pool de threads. Comme les tâches callable s’exécutent en parallèle, nous devons attendre l’objet retourné.
Java Future
Les tâches Java Callable renvoient un objet java.util.concurrent.Future. En utilisant l’objet Java Future, nous pouvons connaître le statut de la tâche Callable et obtenir l’objet retourné. Il propose la méthode get() qui peut attendre que la tâche Callable se termine avant de renvoyer le résultat. Java Future propose la méthode cancel() pour annuler la tâche Callable associée. Il existe une version surchargée de la méthode get() où nous pouvons spécifier le temps d’attente du résultat, ce qui est utile pour éviter le blocage du thread actuel pendant une période plus longue. Les méthodes isDone() et isCancelled() permettent de connaître le statut actuel de la tâche Callable associée. Voici un exemple simple de tâche Java Callable qui renvoie le nom du thread exécutant la tâche après une seconde. Nous utilisons le framework Executor pour exécuter 100 tâches en parallèle et utilisons Java Future pour obtenir le résultat des tâches soumises.
package com.journaldev.threads;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class MyCallable implements Callable {
@Override
public String call() throws Exception {
Thread.sleep(1000);
//retourner le nom du fil exécutant cette tâche appelable
return Thread.currentThread().getName();
}
public static void main(String args[]){
//Obtenez ExecutorService à partir de la classe utilitaire Executors, la taille de la piscine de threads est de 10
ExecutorService executor = Executors.newFixedThreadPool(10);
//créer une liste pour contenir l'objet Future associé à Callable
List> list = new ArrayList>();
//Créer une instance de MyCallable
Callable callable = new MyCallable();
for(int i=0; i< 100; i++){
//soumettre des tâches appelables à exécuter par la piscine de threads
Future future = executor.submit(callable);
//ajouter Future à la liste, nous pouvons obtenir la valeur de retour en utilisant Future
list.add(future);
}
for(Future fut : list){
try {
//afficher la valeur de retour du Future, remarquez le délai de sortie dans la console
//parce que Future.get() attend que la tâche soit terminée
System.out.println(new Date()+ "::"+fut.get());
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
//arrêter le service d'exécution maintenant
executor.shutdown();
}
}
Une fois que nous avons exécuté le programme ci-dessus, vous remarquerez le retard de la sortie car la méthode java Future get() attend que la tâche appelable Java soit terminée. Remarquez également qu’il n’y a que 10 threads qui exécutent ces tâches. Voici un extrait de la sortie du programme ci-dessus.
Mon Dec 31 20:40:15 PST 2012::pool-1-thread-1
Mon Dec 31 20:40:16 PST 2012::pool-1-thread-2
Mon Dec 31 20:40:16 PST 2012::pool-1-thread-3
Mon Dec 31 20:40:16 PST 2012::pool-1-thread-4
Mon Dec 31 20:40:16 PST 2012::pool-1-thread-5
Mon Dec 31 20:40:16 PST 2012::pool-1-thread-6
Mon Dec 31 20:40:16 PST 2012::pool-1-thread-7
Mon Dec 31 20:40:16 PST 2012::pool-1-thread-8
Mon Dec 31 20:40:16 PST 2012::pool-1-thread-9
Mon Dec 31 20:40:16 PST 2012::pool-1-thread-10
Mon Dec 31 20:40:16 PST 2012::pool-1-thread-2
...
Astuce: Et si nous voulons remplacer certaines des méthodes de l’interface Java Future, par exemple en remplaçant la méthode get()
pour dépasser un certain temps par défaut plutôt que d’attendre indéfiniment, dans ce cas, la classe Java FutureTask est pratique car c’est l’implémentation de base de l’interface Future. Consultez Exemple de tâche future Java pour en savoir plus sur cette classe.
Source:
https://www.digitalocean.com/community/tutorials/java-callable-future-example