L'interface Runnable existe depuis le début de la plateforme Java et permet de créer des threads. Cette interface propose la méthode run qui ne prend aucun argument et ne retourne aucune valeur. Si on doit récupérer le résultat de calcul ou de l'exécution d'un thread, il faudrait passer par une classe intermédiaire et attendre la fin du thread pour récupérer le résultat. Par exemple :
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Runnable runnable = ...; | |
Thread t = new Thread(runnable); | |
t.start(); | |
t.join(); | |
String value = someMethodtoGetSavedValue() |
Depuis Java 5, cela devient encore plus facile avec l'interface Callable. Cette interface est identique à Runnable sauf qu'elle définit la méthode call().
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public interface Callable<V> { | |
V call() throws Exception; | |
} |
Pour lancer un Callable, il faut passer l'objet Callable à un ExecutorService via la méthode submit dont voici la signature :
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<T> Future<T> submit(Callable<T> task) |
Comme l'implémentation des ExecutorService exécutent généralement leurs tâches de façon asynchrone, la méthode submit ne peut pas retourner le résultat de la méthode call. Elle retourne plutôt un objet de type Future qui est paramétré par le type du résultat du callable. L'objet Future est simplement une promesse de résultat dans le futur.
La méthode get() de l'objet Future renvoie le résultat et sera bloqué jusqu'à ce que la tâche soit terminée. Cette méthode est équivalente à un join().
Imaginons un programme qui lance des objets Callable convertissant un String en majuscule. Voici le code :
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.grosdim.randomCallable; | |
public class CallableExample { | |
static final int NB_THREADS = 5; | |
public static class StringCallable implements Callable<String>{ | |
private String stringToUpper; | |
public StringCallable(String string){ | |
this.stringToUpper = string; | |
} | |
@Override | |
public String call() throws Exception { | |
return this.stringToUpper.toUpperCase(); | |
} | |
} | |
public static void main(String[] args) throws InterruptedException, ExecutionException{ | |
List<Future<String>> futures = new ArrayList<Future<String>>(); | |
ExecutorService executor = Executors.newFixedThreadPool(NB_THREADS); | |
String[] stringArray = {"java", "callable", "myblog", "hello world", "bonjour tout le monde", "What's going on", "etc"}; | |
for( String s : stringArray){ | |
Callable<String> callable = new StringCallable(s); | |
Future<String> future = executor.submit(callable); | |
futures.add(future); | |
} | |
for(Future<String> f : futures){ | |
String result = f.get(); | |
System.out.println(result); | |
} | |
} | |
} |
Chaque objet de type StringCallable reçoit un String en paramètre et renvoie sa conversion en majuscule via la méthode call. On passe cet objet à un ExecutorService via la méthode submit qui renvoie un objet de type Future. Pour récupérer le résultat, on utilise la méthode get().
Dans cet exemple, on a utilisé un ExecutorService pour lancer un Callable mais n'importe quel Executor fera l'affaire. Pour plus d'informations sur les Executors, je vous invite à visiter cette page.
Aucun commentaire:
Enregistrer un commentaire