@JosePaumard
asynchrones
Java
#J8Async @JosePaumard
Asynchrone ?
#J8Async @JosePaumard
AsynchroneAsynchrone
• Trois tâches à exécuter
T1
T2
T3
#J8Async @JosePaumard
AsynchroneAsynchrone
• 1ère façon de faire :
« exécution synchrone »
#J8Async @JosePaumard
AsynchroneAsynchrone
• 2ème façon de faire :
« exécution multithread »
#J8Async @JosePaumard
AsynchroneAsynchrone
• 2ème façon de faire :
« exécution multithread » … sur un seul cœur
#J8Async @JosePaumard
AsynchroneAsynchrone
• 3ème façon de faire :
« asynchrone »
#J8Async @JosePaumard
AsynchroneAsynchrone
• 3ème façon de faire :
« asynchrone » … même sur un multicœur
#J8Async @JosePaumard
AsynchroneAsynchrone
• 3ème façon de faire :
• Plus rapide ?
#J8Async @JosePaumard
• 3ème façon de faire :
• Plus rapide ?
 En général oui
 Approche « non blocking »
AsynchroneAsynchrone
#J8Async @JosePaumard
• Différence avec le modèle synchrone multithread ?
1) Le traitement décide de passer d’une tâche à l’autre
2) Pas de problème d’atomicité / visibilité
• Performances ?
 Pas de « context switch »
AsynchroneAsynchrone
#J8Async @JosePaumard
• Pattern
AsynchroneAsynchrone
queryEngine.select("select user from User")
.forEach(user ‐> System.out.prinln(user)) ;
#J8Async @JosePaumard
• Pattern
• Callback ou tâche : lambda expression
AsynchroneAsynchrone
queryEngine.select("select user from User")
.forEach(user ‐> System.out.prinln(user)) ;
#J8Async @JosePaumard
• Pattern
• Callback ou tâche : lambda expression
• Enchaînement : lorsque le résultat est disponible
alors on enchaîne avec le traitement
AsynchroneAsynchrone
queryEngine.select("select user from User")
.forEach(System.out::prinln) ;
#J8Async @JosePaumard
• Pattern
• Callback ou tâche : lambda expression
• Enchaînement : lorsque le résultat est disponible
alors on enchaîne avec le traitement
• Comment écrire ceci en Java ?
AsynchroneAsynchrone
queryEngine.select("select user from User")
.forEach(System.out::prinln) ;
#J8Async @JosePaumard
Notion de tâcheNotion de tâche
• Depuis Java 1 : Runnable
• Java 5 : Callable
• Java 5 : ExecutorService (pool de threads)
• On donne une tâche, on récupère un Future
#J8Async @JosePaumard
Notion de tâcheNotion de tâche
• Pattern
Callable<String> task = () ‐> "select user from User" ;
Future<String> future = executorService.submit(task) ;
#J8Async @JosePaumard
Notion de tâcheNotion de tâche
• Pattern
Callable<String> task = () ‐> "select user from User" ;
Future<String> future = executorService.submit(task) ;
List<User> users = future.get() ;    // blocking
users.forEach(System.out::println) ;
#J8Async @JosePaumard
Notion de tâcheNotion de tâche
• Pattern
• Le passage d’un objet d’une tâche à l’autre se fait
dans le thread « maître »
Callable<String> task = () ‐> "select user from User" ;
Future<String> future = executorService.submit(task) ;
List<User> users = future.get() ;    // blocking
users.forEach(System.out::println) ;
#J8Async @JosePaumard
Programmation asynchroneProgrammation asynchrone
• Nouveaux outils en Java 8 pour traiter ce point
• Solution pour enchaîner les tâches
• Asynchrone & multithread
#J8Async @JosePaumard
Questions ?
#J8Async
Questions ?
#J8Async
#J8Async @JosePaumard
• Nouvelle interface en Java 8 : CompletionStage
De quoi s’agit-il ?De quoi s’agit-il ?
/**
* A stage of a possibly asynchronous computation, that performs an
* action or computes a value when another CompletionStage completes.
* A stage completes upon termination of its computation, but this may
* in turn trigger other dependent stages.
*/
#J8Async @JosePaumard
• Nouvelle interface en Java 8 : CompletionStage
• CompletionStage = une tâche qui se déclenche sur
une autre et qui peut en déclencher d’autres
De quoi s’agit-il ?De quoi s’agit-il ?
/**
* A stage of a possibly asynchronous computation, that performs an
* action or computes a value when another CompletionStage completes.
* A stage completes upon termination of its computation, but this may
* in turn trigger other dependent stages
*/
#J8Async @JosePaumard
• Classe d’implémentation : CompletableFuture
• Implémente à la fois :
 Future
 CompletionStage
De quoi s’agit-il ?De quoi s’agit-il ?
#J8Async @JosePaumard
• CompletableFuture : modélise une tâche
• Peut être dans trois états :
De quoi s’agit-il ?De quoi s’agit-il ?
#J8Async @JosePaumard
• CompletableFuture : modélise une tâche
• Peut être dans trois états :
 En train d’être calculée
De quoi s’agit-il ?De quoi s’agit-il ?
#J8Async @JosePaumard
• CompletableFuture : modélise une tâche
• Peut être dans trois états :
 En train d’être calculée
 Calculée, ayant produit un résultat
De quoi s’agit-il ?De quoi s’agit-il ?
#J8Async @JosePaumard
• CompletableFuture : modélise une tâche
• Peut être dans trois états :
 En train d’être calculée
 Calculée, ayant produit un résultat
 Calculée, ayant généré une exception
De quoi s’agit-il ?De quoi s’agit-il ?
#J8Async @JosePaumard
FutureFuture
• Cinq méthodes :
boolean cancel(boolean mayInterruptIfRunning) ;
#J8Async @JosePaumard
FutureFuture
• Cinq méthodes :
boolean cancel(boolean mayInterruptIfRunning) ;
boolean isCanceled() ;
boolean isDone() ;
#J8Async @JosePaumard
FutureFuture
• Cinq méthodes :
boolean cancel(boolean mayInterruptIfRunning) ;
boolean isCanceled() ;
boolean isDone() ;
V get() ; // blocking call 
V get(long timeout, TimeUnit timeUnit) ; // may throw a checked exception
throws InterruptedException, ExecutionException, TimeoutException ;
#J8Async @JosePaumard
CompletableFutureCompletableFuture
• Méthodes de type « future » :
V join() ; // may throw an unchecked exception
V getNow(V valueIfAbsent) ; // returns immediately
#J8Async @JosePaumard
CompletableFutureCompletableFuture
• Méthodes de type « future » :
V join() ; // may throw an unchecked exception
V getNow(V valueIfAbsent) ; // returns immediately
boolean complete(V value) ;  // sets the returned value is not returned
void obtrudeValue(V value) ; // resets the returned value 
#J8Async @JosePaumard
CompletableFutureCompletableFuture
• Méthodes de type « future » :
V join() ; // may throw an unchecked exception
V getNow(V valueIfAbsent) ; // returns immediately
boolean complete(V value) ;  // sets the returned value is not returned
void obtrudeValue(V value) ; // resets the returned value 
boolean completeExceptionnaly(Throwable t) ;  // sets an exception
void obtrudeException(Throwable t) ; // resets with an exception
#J8Async @JosePaumard
Création d’un CompletableFutureCréation d’un CompletableFuture
• CompletableFuture déjà terminé
public static <U> CompletableFuture<U> completedFuture(U value) ;
#J8Async @JosePaumard
Création d’un CompletableFutureCréation d’un CompletableFuture
• CompletableFuture déjà terminé
public static <U> CompletableFuture<U> completedFuture(U value) ;
public static <U> CompletableFuture<U> 
supplyAsync(Supplier<U> value, Executor executor) ;
public static <U> CompletableFuture<U> 
runAsync(Runnable runnable, Executor executor) ;
#J8Async @JosePaumard
CompletionStageCompletionStage
• Concept : un étape dans un traitement global
 Peut être déclenchée par une étape précédente
 Peut déclencher d’autres étapes
 Peut être exécutée dans un executor particulier
#J8Async @JosePaumard
CompletionStageCompletionStage
• Notion tâche :
 Function : prend un argument, retourne une valeur
 Consumer : prend un argument
 Runnable
= interfaces fonctionnelles, donc lambda
#J8Async @JosePaumard
CompletionStage – chaînageCompletionStage – chaînage
• Chaînage après, même thread
public <U> CompletionStage<U> 
thenApply(Function<? super T,? extends U> fn);
public CompletionStage<Void> 
thenAccept(Consumer<? super T> action);
public CompletionStage<Void> 
thenRun(Runnable action);
#J8Async @JosePaumard
CompletionStage – chaînageCompletionStage – chaînage
• Chaînage après, autre thread (common FJ pool)
public <U> CompletionStage<U> 
thenApplyAsync(Function<? super T,? extends U> fn);
public CompletionStage<Void> 
thenAcceptAsync(Consumer<? super T> action);
public CompletionStage<Void> 
thenRunAsync(Runnable action);
#J8Async @JosePaumard
CompletionStage – chaînageCompletionStage – chaînage
• Chaînage après, autre thread (executor)
public <U> CompletionStage<U> 
thenApplyAsync(Function<? super T,? extends U> fn, Executor executor);
public CompletionStage<Void> 
thenAcceptAsync(Consumer<? super T> action, Executor executor);
public CompletionStage<Void> 
thenRunAsync(Runnable action, Executor executor);
#J8Async @JosePaumard
CompletionStage – compositionCompletionStage – composition
• Composition
public <U> CompletionStage<U> 
thenCompose(Function<? super T, ? extends CompletionStage<U>> fn);
public CompletionStage<Void> 
thenComposeAsync(
Function<? super T, ? extends CompletionStage<U>> fn);
public CompletionStage<Void> 
thenComposeAsync(
Function<? super T, ? extends CompletionStage<U>> fn,
Executor executor);
#J8Async @JosePaumard
Chaînage & compositionChaînage & composition
• Ces deux familles de fonction permettent d’enchaîner
une opération après l’autre
#J8Async @JosePaumard
Chaînage & compositionChaînage & composition
• On peut aussi enchaîner une tâche à la suite de deux
autres tâches
public CompletionStage<V> thenCombine
(CompletionStage<U> other, 
BiFunction<T, U, V> function) ;
#J8Async @JosePaumard
Chaînage & compositionChaînage & composition
• On peut aussi enchaîner une tâche à la suite de deux
autres tâches
• Prend les résultats de this et other
 Et les combine dans function
public CompletionStage<V> thenCombine
(CompletionStage<U> other, 
BiFunction<T, U, V> function) ;
#J8Async @JosePaumard
Chaînage & compositionChaînage & composition
• On peut aussi enchaîner une tâche à la suite de deux
autres tâches
public CompletionStage<V> thenCombine
(CompletionStage<U> other, 
BiFunction<T, U, V> function) ;
public CompletionStage<V> thenCombineAsync
(CompletionStage<U> other, 
BiFunction<T, U, V> function) ;
#J8Async @JosePaumard
Chaînage & compositionChaînage & composition
• On peut aussi enchaîner une tâche à la suite de deux
autres tâches
public CompletionStage<V> thenCombine
(CompletionStage<U> other, 
BiFunction<T, U, V> function) ;
public CompletionStage<V> thenCombineAsync
(CompletionStage<U> other, 
BiFunction<T, U, V> function, Executor executor) ;
#J8Async @JosePaumard
Chaînage & compositionChaînage & composition
• Versions avec Consumer
public CompletionStage<Void> thenAcceptBoth
(CompletionStage<U> other, 
BiConsumer<T, U> action) ;
public CompletionStage<Void> thenAcceptBothAsync
(CompletionStage<U> other, 
BiConsumer<T, U> action) ;
public CompletionStage<Void> thenAcceptBothAsync
(CompletionStage<U> other, 
BiConsumer<T, U> action, Executor executor) ;
#J8Async @JosePaumard
Chaînage & compositionChaînage & composition
• Versions avec Runnable
public CompletionStage<Void> runAfterBoth
(CompletionStage<?> other, 
Runnable action) ;
public CompletionStage<Void> runAfterBothAsync
(CompletionStage<?> other, 
Runnable action) ;
public CompletionStage<Void> runAfterBothAsync
(CompletionStage<?> other, 
Runnable action, Executor executor) ;
#J8Async @JosePaumard
Chaînage & compositionChaînage & composition
• Ces tâches se déclenchent conditionnellement à this
et à la tâche passée en paramètre
• Lorsque ces tâches sont terminées
• On peut aussi déclencher lorsque la première se
termine
#J8Async @JosePaumard
Chaînage multipleChaînage multiple
• Version function
public CompletionStage<V> applyToEither
(CompletionStage<? extends T> other, 
Function<T, U> function) ;
#J8Async @JosePaumard
Chaînage multipleChaînage multiple
• Version function
public CompletionStage<U> applyToEither
(CompletionStage<? extends T> other, 
Function<T, U> function) ;
public CompletionStage<U> applyToEitherAsync
(CompletionStage<? extends T> other, 
Function<T, U> function) ;
public CompletionStage<U> applyToEitherAsync
(CompletionStage<? extends T> other, 
Function<T, U> function, Executor executor) ;
#J8Async @JosePaumard
Chaînage multipleChaînage multiple
• Version consumer
public CompletionStage<V> acceptEither
(CompletionStage<? extends T> other, 
Consumer<? extends T> consumer) ;
public CompletionStage<V> acceptEitherAsync
(CompletionStage<? extends T> other, 
Consumer<? extends T> consumer) ;
public CompletionStage<V> acceptEitherAsync
(CompletionStage<? extends T> other, 
Consumer<? extends T> consumer, Executor executor) ;
#J8Async @JosePaumard
Chaînage multipleChaînage multiple
• Version runnable
public CompletionStage<V> runAfterEither
(CompletionStage<U> other, 
Runnable action) ;
public CompletionStage<V> runAfterEitherAsync
(CompletionStage<U> other, 
Runnable action) ;
public CompletionStage<V> runAfterEitherAsync
(CompletionStage<U> other, 
Runnable action, Executor executor) ;
#J8Async @JosePaumard
Création sur plusieurs tâchesCréation sur plusieurs tâches
• Méthodes statiques
public static CompletableFuture<Void> 
allOf(CompletableFuture<?>... cfs) ;
public static CompletableFuture<Object> 
anyOf(CompletableFuture<?>... cfs) ;
#J8Async @JosePaumard
Création sur plusieurs tâchesCréation sur plusieurs tâches
• Attention à la sémantique !
• Imprime « null »
public static CompletableFuture<Void> 
allOf(CompletableFuture<?>... cfs) ;
CompletableFuture<Void> allOf = CompletableFuture.allOf() ;
System.out.println("allOF : " + allOf.join()) ;
#J8Async @JosePaumard
Création sur plusieurs tâchesCréation sur plusieurs tâches
• Attention à la sémantique !
• Ne rend pas la main…
public static CompletableFuture<Void> 
allOf(CompletableFuture<?>... cfs) ;
CompletableFuture<Object> anyOf = CompletableFuture.anyOf() ;
System.out.println("anyOf : " + anyOf.join()) ;
#J8Async @JosePaumard
Création sur plusieurs tâchesCréation sur plusieurs tâches
• Attention à la sémantique !
public static CompletableFuture<Void> 
allOf(CompletableFuture<?>... cfs) ;
CompletableFuture<Object> anyOf = CompletableFuture.anyOf() ;
System.out.println("anyOf : " + anyOf.getNow("Nothing to say")) ;
#J8Async @JosePaumard
Gestion des exceptionsGestion des exceptions
• Point délicat :
 Une première étape consiste à créer les tâches et à
décrire leur enchaînement
 L’exécution des tâches démarre indépendamment des
appels
 À chaque étape, un CompletableFuture est créé
#J8Async @JosePaumard
Gestion des exceptionsGestion des exceptions
• Un CompletableFuture peut dépendre :
 Cas 1 : d’un autre CompletableFuture
 Cas 2 : de deux autres CompletableFuture
 Cas 3 : de N CompletableFuture
#J8Async @JosePaumard
Gestion des exceptionsGestion des exceptions
• Une exception est jetée dans le cas 1
 Tous les CompletableFuture sont en erreur
• Ils se terminent « exceptionnellement »
 isExceptionnaly() retourne true
 L’appel à get() jette une ExecutionException
 get().getCause() retourne l’exception première
#J8Async @JosePaumard
Gestion des exceptionsGestion des exceptions
• Une exception est jetée dans le cas 2
 Tous les CompletableFuture en aval sont en erreur
• Ils se terminent « exceptionnellement »
• L’autre tâche peut se terminer normalement
 On peut l’interroger par get() pour avoir son résultat
#J8Async @JosePaumard
Gestion des exceptionsGestion des exceptions
• Une exception est jetée dans le cas 3
 Le CompletableFuture retourné est en erreur
• Il se termine « exceptionnellement »
• Les autres tâches peuvent se terminer normalement
 On peut l’interroger par get() pour avoir son résultat
#J8Async @JosePaumard
Gestion des exceptionsGestion des exceptions
• On peut aussi traiter une exception normalement
 Dans ce cas, l’exception est passée à la fonction
 Utile pour les checked exception
CompletionStage<T> exceptionally(
Function<Throwable, ? extends T> function);
#J8Async @JosePaumard
Gestion des exceptionsGestion des exceptions
• Méthode whenComplete()
 Dans ce cas t ou e est nul dans l’appel de action
 Le CompletableFuture retourné peut ne pas être en
erreur
CompletionStage<T> whenComplete
(BiConsumer<T, Throwable> action) ;
#J8Async @JosePaumard
Gestion des exceptionsGestion des exceptions
• Méthode whenComplete()
CompletionStage<T> whenComplete
(BiConsumer<T, Throwable> action) ;
CompletionStage<T> whenCompleteAsync
(BiConsumer<T, Throwable> action) ;
CompletionStage<T> whenCompleteAsync
(BiConsumer<T, Throwable> action, Executor executor) ;
#J8Async @JosePaumard
Gestion des exceptionsGestion des exceptions
• Méthode handle()
 Dans ce cas t ou e est nul dans l’appel de function
 Retourne un CompletableFuture qui peut ne pas être
en erreur
CompletionStage<T> handle
(BiFunction<T, Throwable, U> function) ;
#J8Async @JosePaumard
Gestion des exceptionsGestion des exceptions
• Méthode handle()
CompletionStage<T> handle
(BiFunction<T, Throwable, U> function) ;
CompletionStage<T> handleAsync
(BiFunction<T, Throwable, U> function) ;
CompletionStage<T> handleAsync
(BiFunction<T, Throwable, U> function, Executor executor) ;
#J8Async @JosePaumard
Une dernière méthodeUne dernière méthode
• CompletableFuture : On peut obtenir une estimation
du nombre de tâches qui attendent l’exécution d’une
tâche donnée
int getNumberOfDependents() ;
#J8Async @JosePaumard
Exemple – 1Exemple – 1
• Lecture asynchrone de liens et affichage
CompletableFuture.supplyAsync(
() ‐> readPage("http://whatever.com/")
)
#J8Async @JosePaumard
Exemple – 1Exemple – 1
• Lecture asynchrone de liens et affichage
CompletableFuture.supplyAsync(
() ‐> readPage("http://whatever.com/")
)
.thenApply(page ‐> linkParser.getLinks(page))
#J8Async @JosePaumard
Exemple – 1Exemple – 1
• Lecture asynchrone de liens et affichage
CompletableFuture.supplyAsync(
() ‐> readPage("http://whatever.com/")
)
.thenApply(page ‐> linkParser.getLinks(page))
.thenAccept(
links ‐> displayPanel.display(links)
) ;
#J8Async @JosePaumard
Exemple – 1Exemple – 1
• Lecture asynchrone de liens et affichage
CompletableFuture.supplyAsync(
() ‐> readPage("http://whatever.com/")
)
.thenApply(page ‐> linkParser.getLinks(page))
.thenAcceptAsync(
links ‐> displayPanel.display(links),
executor
) ;
#J8Async @JosePaumard
Exemple – 1Exemple – 1
• Lecture asynchrone de liens et affichage
public interface Executor {
void execute(Runnable command);
}
#J8Async @JosePaumard
Exemple – 1Exemple – 1
• Lecture asynchrone de liens et affichage
public interface Executor {
void execute(Runnable command);
}
Executor executor = runnable ‐> SwingUtilities.invokeLater(runnable) ;
#J8Async @JosePaumard
Exemple – 1Exemple – 1
• Lecture asynchrone de liens et affichage
CompletableFuture.supplyAsync(
() ‐> readPage("http://whatever.com/")
)
.thenApply(page ‐> linkParser.getLinks(page))
.thenAcceptAsync(
links ‐> displayPanel.display(links), 
runnable ‐> SwingUtilities.invokeLater(runnable)
) ;
#J8Async @JosePaumard
Exemple – 1Exemple – 1
• Lecture asynchrone de liens et affichage
CompletableFuture.supplyAsync(
() ‐> readPage("http://whatever.com/")
)
.thenApply(Parser::getLinks)
.thenAcceptAsync(
DisplayPanel::display, 
SwingUtilities::invokeLater
) ;
#J8Async @JosePaumard
Exemple – 2Exemple – 2
• Événements asynchrones dans CDI
@Inject
Event<String> event ;
event.fire("some event") ; // returns void
public void observes(@Observes String payload) {
// handle the event, called in the firing thread
}
#J8Async @JosePaumard
Exemple – 2Exemple – 2
• Événements asynchrones dans CDI
public void observes(@Observes String payload) {
// handle the event, called in the firing thread
CompletableFuture.anyOf(/* some task */) ;
}
#J8Async @JosePaumard
Exemple – 2Exemple – 2
• Événements asynchrones dans CDI
@Inject
Event<String> event ;
event.fireAsync("some event") ; // returns CompletableFuture<Object> (?)
public void observes(@Observes String payload) {
// handle the event in another thread
}
#J8Async @JosePaumard
Exemple – 2Exemple – 2
• Événements asynchrones dans CDI
@Inject
Event<String> event ;
event.fireAsync("some event", executor) ; 
public void observes(@Observes String payload) {
// handle the event in the executor
}
#J8Async @JosePaumard
Exemple – 2Exemple – 2
• Événements asynchrones dans CDI
@Inject
Event<String> event ;
event.fireAsync("some event", executor) ; 
@Produces @SwingExecutor
Executor executor = SwingUtilities::invokeLater
public void observes(@Observes String payload, 
@SwingExecutor Executor executor) {
// handle the event in the Swing thread
}
#J8Async @JosePaumard
Exemple – 2Exemple – 2
• Événements asynchrones dans CDI
@Inject
Event<String> event ;
event.fireAsync("some event", executor) ; 
@Produces @SwingExecutor
Executor executor = SwingUtilities::invokeLater
public void observes(@Observes @SwingExecutor String payload) {
// handle the event in the Swing thread
}
#J8Async @JosePaumard
Exemple – 3Exemple – 3
CompletableFuture<String> closing = new CompletableFuture<String>() ;
Stream<String> manyStrings = Stream.of("one", "two", "three") ;
CompletableFuture<String> reduce =
manyStrings
.onClose(() ‐> { closing.complete("Closed") ; })
.map(CompletableFuture::completedFuture)
.reduce(
closing,  
(cf1, cf2) ‐> cf1.thenCombine(cf2, function) // concatenation
) ;
manyStrings.close() ;
#J8Async @JosePaumard
L’indispensable !L’indispensable !
• Fixer la taille du Common Fork / Join Pool
System.setProperty(
"java.util.concurrent.ForkJoinPool.common.parallelism", 2) ;
#J8Async @JosePaumard
ConclusionConclusion
• On a une API pour le calcul asynchrone dans le JDK !
#J8Async @JosePaumard
ConclusionConclusion
• On a une API pour le calcul asynchrone dans le JDK !
• Très riche et souple à l’utilisation
#J8Async @JosePaumard
ConclusionConclusion
• On a une API pour le calcul asynchrone dans le JDK !
• Très riche et souple à l’utilisation
• Construite sur l’utilisation des lambda
#J8Async @JosePaumard
ConclusionConclusion
• On a une API pour le calcul asynchrone dans le JDK !
• Très riche et souple à l’utilisation
• Construite sur l’utilisation des lambda
• Permet un contrôle fin des threads
#J8Async @JosePaumard
ConclusionConclusion
• On a une API pour le calcul asynchrone dans le JDK !
• Très riche et souple à l’utilisation
• Construite sur l’utilisation des lambda
• Permet un contrôle fin des threads
• Gère différents types de chaînage
#J8Async @JosePaumard
ConclusionConclusion
• On a une API pour le calcul asynchrone dans le JDK !
• Très riche et souple à l’utilisation
• Construite sur l’utilisation des lambda
• Permet un contrôle fin des threads
• Gère différents types de chaînage
• Gère intelligemment les exceptions
@JosePaumard#J8Stream
@JosePaumard#J8Stream

API Asynchrones en Java 8

  • 1.
  • 2.
  • 3.
  • 4.
    #J8Async @JosePaumard AsynchroneAsynchrone • 1èrefaçon de faire : « exécution synchrone »
  • 5.
    #J8Async @JosePaumard AsynchroneAsynchrone • 2èmefaçon de faire : « exécution multithread »
  • 6.
    #J8Async @JosePaumard AsynchroneAsynchrone • 2èmefaçon de faire : « exécution multithread » … sur un seul cœur
  • 7.
    #J8Async @JosePaumard AsynchroneAsynchrone • 3èmefaçon de faire : « asynchrone »
  • 8.
    #J8Async @JosePaumard AsynchroneAsynchrone • 3èmefaçon de faire : « asynchrone » … même sur un multicœur
  • 9.
    #J8Async @JosePaumard AsynchroneAsynchrone • 3èmefaçon de faire : • Plus rapide ?
  • 10.
    #J8Async @JosePaumard • 3èmefaçon de faire : • Plus rapide ?  En général oui  Approche « non blocking » AsynchroneAsynchrone
  • 11.
    #J8Async @JosePaumard • Différenceavec le modèle synchrone multithread ? 1) Le traitement décide de passer d’une tâche à l’autre 2) Pas de problème d’atomicité / visibilité • Performances ?  Pas de « context switch » AsynchroneAsynchrone
  • 12.
  • 13.
    #J8Async @JosePaumard • Pattern •Callback ou tâche : lambda expression AsynchroneAsynchrone queryEngine.select("select user from User") .forEach(user ‐> System.out.prinln(user)) ;
  • 14.
    #J8Async @JosePaumard • Pattern •Callback ou tâche : lambda expression • Enchaînement : lorsque le résultat est disponible alors on enchaîne avec le traitement AsynchroneAsynchrone queryEngine.select("select user from User") .forEach(System.out::prinln) ;
  • 15.
    #J8Async @JosePaumard • Pattern •Callback ou tâche : lambda expression • Enchaînement : lorsque le résultat est disponible alors on enchaîne avec le traitement • Comment écrire ceci en Java ? AsynchroneAsynchrone queryEngine.select("select user from User") .forEach(System.out::prinln) ;
  • 16.
    #J8Async @JosePaumard Notion detâcheNotion de tâche • Depuis Java 1 : Runnable • Java 5 : Callable • Java 5 : ExecutorService (pool de threads) • On donne une tâche, on récupère un Future
  • 17.
    #J8Async @JosePaumard Notion detâcheNotion de tâche • Pattern Callable<String> task = () ‐> "select user from User" ; Future<String> future = executorService.submit(task) ;
  • 18.
    #J8Async @JosePaumard Notion detâcheNotion de tâche • Pattern Callable<String> task = () ‐> "select user from User" ; Future<String> future = executorService.submit(task) ; List<User> users = future.get() ;    // blocking users.forEach(System.out::println) ;
  • 19.
    #J8Async @JosePaumard Notion detâcheNotion de tâche • Pattern • Le passage d’un objet d’une tâche à l’autre se fait dans le thread « maître » Callable<String> task = () ‐> "select user from User" ; Future<String> future = executorService.submit(task) ; List<User> users = future.get() ;    // blocking users.forEach(System.out::println) ;
  • 20.
    #J8Async @JosePaumard Programmation asynchroneProgrammationasynchrone • Nouveaux outils en Java 8 pour traiter ce point • Solution pour enchaîner les tâches • Asynchrone & multithread
  • 26.
  • 27.
    #J8Async @JosePaumard • Nouvelleinterface en Java 8 : CompletionStage De quoi s’agit-il ?De quoi s’agit-il ? /** * A stage of a possibly asynchronous computation, that performs an * action or computes a value when another CompletionStage completes. * A stage completes upon termination of its computation, but this may * in turn trigger other dependent stages. */
  • 28.
    #J8Async @JosePaumard • Nouvelleinterface en Java 8 : CompletionStage • CompletionStage = une tâche qui se déclenche sur une autre et qui peut en déclencher d’autres De quoi s’agit-il ?De quoi s’agit-il ? /** * A stage of a possibly asynchronous computation, that performs an * action or computes a value when another CompletionStage completes. * A stage completes upon termination of its computation, but this may * in turn trigger other dependent stages */
  • 29.
    #J8Async @JosePaumard • Classed’implémentation : CompletableFuture • Implémente à la fois :  Future  CompletionStage De quoi s’agit-il ?De quoi s’agit-il ?
  • 30.
    #J8Async @JosePaumard • CompletableFuture: modélise une tâche • Peut être dans trois états : De quoi s’agit-il ?De quoi s’agit-il ?
  • 31.
    #J8Async @JosePaumard • CompletableFuture: modélise une tâche • Peut être dans trois états :  En train d’être calculée De quoi s’agit-il ?De quoi s’agit-il ?
  • 32.
    #J8Async @JosePaumard • CompletableFuture: modélise une tâche • Peut être dans trois états :  En train d’être calculée  Calculée, ayant produit un résultat De quoi s’agit-il ?De quoi s’agit-il ?
  • 33.
    #J8Async @JosePaumard • CompletableFuture: modélise une tâche • Peut être dans trois états :  En train d’être calculée  Calculée, ayant produit un résultat  Calculée, ayant généré une exception De quoi s’agit-il ?De quoi s’agit-il ?
  • 34.
    #J8Async @JosePaumard FutureFuture • Cinqméthodes : boolean cancel(boolean mayInterruptIfRunning) ;
  • 35.
    #J8Async @JosePaumard FutureFuture • Cinqméthodes : boolean cancel(boolean mayInterruptIfRunning) ; boolean isCanceled() ; boolean isDone() ;
  • 36.
    #J8Async @JosePaumard FutureFuture • Cinqméthodes : boolean cancel(boolean mayInterruptIfRunning) ; boolean isCanceled() ; boolean isDone() ; V get() ; // blocking call  V get(long timeout, TimeUnit timeUnit) ; // may throw a checked exception throws InterruptedException, ExecutionException, TimeoutException ;
  • 37.
    #J8Async @JosePaumard CompletableFutureCompletableFuture • Méthodesde type « future » : V join() ; // may throw an unchecked exception V getNow(V valueIfAbsent) ; // returns immediately
  • 38.
    #J8Async @JosePaumard CompletableFutureCompletableFuture • Méthodesde type « future » : V join() ; // may throw an unchecked exception V getNow(V valueIfAbsent) ; // returns immediately boolean complete(V value) ;  // sets the returned value is not returned void obtrudeValue(V value) ; // resets the returned value 
  • 39.
    #J8Async @JosePaumard CompletableFutureCompletableFuture • Méthodesde type « future » : V join() ; // may throw an unchecked exception V getNow(V valueIfAbsent) ; // returns immediately boolean complete(V value) ;  // sets the returned value is not returned void obtrudeValue(V value) ; // resets the returned value  boolean completeExceptionnaly(Throwable t) ;  // sets an exception void obtrudeException(Throwable t) ; // resets with an exception
  • 40.
    #J8Async @JosePaumard Création d’unCompletableFutureCréation d’un CompletableFuture • CompletableFuture déjà terminé public static <U> CompletableFuture<U> completedFuture(U value) ;
  • 41.
    #J8Async @JosePaumard Création d’unCompletableFutureCréation d’un CompletableFuture • CompletableFuture déjà terminé public static <U> CompletableFuture<U> completedFuture(U value) ; public static <U> CompletableFuture<U>  supplyAsync(Supplier<U> value, Executor executor) ; public static <U> CompletableFuture<U>  runAsync(Runnable runnable, Executor executor) ;
  • 42.
    #J8Async @JosePaumard CompletionStageCompletionStage • Concept: un étape dans un traitement global  Peut être déclenchée par une étape précédente  Peut déclencher d’autres étapes  Peut être exécutée dans un executor particulier
  • 43.
    #J8Async @JosePaumard CompletionStageCompletionStage • Notiontâche :  Function : prend un argument, retourne une valeur  Consumer : prend un argument  Runnable = interfaces fonctionnelles, donc lambda
  • 44.
    #J8Async @JosePaumard CompletionStage –chaînageCompletionStage – chaînage • Chaînage après, même thread public <U> CompletionStage<U>  thenApply(Function<? super T,? extends U> fn); public CompletionStage<Void>  thenAccept(Consumer<? super T> action); public CompletionStage<Void>  thenRun(Runnable action);
  • 45.
    #J8Async @JosePaumard CompletionStage –chaînageCompletionStage – chaînage • Chaînage après, autre thread (common FJ pool) public <U> CompletionStage<U>  thenApplyAsync(Function<? super T,? extends U> fn); public CompletionStage<Void>  thenAcceptAsync(Consumer<? super T> action); public CompletionStage<Void>  thenRunAsync(Runnable action);
  • 46.
    #J8Async @JosePaumard CompletionStage –chaînageCompletionStage – chaînage • Chaînage après, autre thread (executor) public <U> CompletionStage<U>  thenApplyAsync(Function<? super T,? extends U> fn, Executor executor); public CompletionStage<Void>  thenAcceptAsync(Consumer<? super T> action, Executor executor); public CompletionStage<Void>  thenRunAsync(Runnable action, Executor executor);
  • 47.
    #J8Async @JosePaumard CompletionStage –compositionCompletionStage – composition • Composition public <U> CompletionStage<U>  thenCompose(Function<? super T, ? extends CompletionStage<U>> fn); public CompletionStage<Void>  thenComposeAsync( Function<? super T, ? extends CompletionStage<U>> fn); public CompletionStage<Void>  thenComposeAsync( Function<? super T, ? extends CompletionStage<U>> fn, Executor executor);
  • 48.
    #J8Async @JosePaumard Chaînage &compositionChaînage & composition • Ces deux familles de fonction permettent d’enchaîner une opération après l’autre
  • 49.
    #J8Async @JosePaumard Chaînage &compositionChaînage & composition • On peut aussi enchaîner une tâche à la suite de deux autres tâches public CompletionStage<V> thenCombine (CompletionStage<U> other,  BiFunction<T, U, V> function) ;
  • 50.
    #J8Async @JosePaumard Chaînage &compositionChaînage & composition • On peut aussi enchaîner une tâche à la suite de deux autres tâches • Prend les résultats de this et other  Et les combine dans function public CompletionStage<V> thenCombine (CompletionStage<U> other,  BiFunction<T, U, V> function) ;
  • 51.
    #J8Async @JosePaumard Chaînage &compositionChaînage & composition • On peut aussi enchaîner une tâche à la suite de deux autres tâches public CompletionStage<V> thenCombine (CompletionStage<U> other,  BiFunction<T, U, V> function) ; public CompletionStage<V> thenCombineAsync (CompletionStage<U> other,  BiFunction<T, U, V> function) ;
  • 52.
    #J8Async @JosePaumard Chaînage &compositionChaînage & composition • On peut aussi enchaîner une tâche à la suite de deux autres tâches public CompletionStage<V> thenCombine (CompletionStage<U> other,  BiFunction<T, U, V> function) ; public CompletionStage<V> thenCombineAsync (CompletionStage<U> other,  BiFunction<T, U, V> function, Executor executor) ;
  • 53.
    #J8Async @JosePaumard Chaînage &compositionChaînage & composition • Versions avec Consumer public CompletionStage<Void> thenAcceptBoth (CompletionStage<U> other,  BiConsumer<T, U> action) ; public CompletionStage<Void> thenAcceptBothAsync (CompletionStage<U> other,  BiConsumer<T, U> action) ; public CompletionStage<Void> thenAcceptBothAsync (CompletionStage<U> other,  BiConsumer<T, U> action, Executor executor) ;
  • 54.
    #J8Async @JosePaumard Chaînage &compositionChaînage & composition • Versions avec Runnable public CompletionStage<Void> runAfterBoth (CompletionStage<?> other,  Runnable action) ; public CompletionStage<Void> runAfterBothAsync (CompletionStage<?> other,  Runnable action) ; public CompletionStage<Void> runAfterBothAsync (CompletionStage<?> other,  Runnable action, Executor executor) ;
  • 55.
    #J8Async @JosePaumard Chaînage &compositionChaînage & composition • Ces tâches se déclenchent conditionnellement à this et à la tâche passée en paramètre • Lorsque ces tâches sont terminées • On peut aussi déclencher lorsque la première se termine
  • 56.
    #J8Async @JosePaumard Chaînage multipleChaînagemultiple • Version function public CompletionStage<V> applyToEither (CompletionStage<? extends T> other,  Function<T, U> function) ;
  • 57.
    #J8Async @JosePaumard Chaînage multipleChaînagemultiple • Version function public CompletionStage<U> applyToEither (CompletionStage<? extends T> other,  Function<T, U> function) ; public CompletionStage<U> applyToEitherAsync (CompletionStage<? extends T> other,  Function<T, U> function) ; public CompletionStage<U> applyToEitherAsync (CompletionStage<? extends T> other,  Function<T, U> function, Executor executor) ;
  • 58.
    #J8Async @JosePaumard Chaînage multipleChaînagemultiple • Version consumer public CompletionStage<V> acceptEither (CompletionStage<? extends T> other,  Consumer<? extends T> consumer) ; public CompletionStage<V> acceptEitherAsync (CompletionStage<? extends T> other,  Consumer<? extends T> consumer) ; public CompletionStage<V> acceptEitherAsync (CompletionStage<? extends T> other,  Consumer<? extends T> consumer, Executor executor) ;
  • 59.
    #J8Async @JosePaumard Chaînage multipleChaînagemultiple • Version runnable public CompletionStage<V> runAfterEither (CompletionStage<U> other,  Runnable action) ; public CompletionStage<V> runAfterEitherAsync (CompletionStage<U> other,  Runnable action) ; public CompletionStage<V> runAfterEitherAsync (CompletionStage<U> other,  Runnable action, Executor executor) ;
  • 60.
    #J8Async @JosePaumard Création surplusieurs tâchesCréation sur plusieurs tâches • Méthodes statiques public static CompletableFuture<Void>  allOf(CompletableFuture<?>... cfs) ; public static CompletableFuture<Object>  anyOf(CompletableFuture<?>... cfs) ;
  • 61.
    #J8Async @JosePaumard Création surplusieurs tâchesCréation sur plusieurs tâches • Attention à la sémantique ! • Imprime « null » public static CompletableFuture<Void>  allOf(CompletableFuture<?>... cfs) ; CompletableFuture<Void> allOf = CompletableFuture.allOf() ; System.out.println("allOF : " + allOf.join()) ;
  • 62.
    #J8Async @JosePaumard Création surplusieurs tâchesCréation sur plusieurs tâches • Attention à la sémantique ! • Ne rend pas la main… public static CompletableFuture<Void>  allOf(CompletableFuture<?>... cfs) ; CompletableFuture<Object> anyOf = CompletableFuture.anyOf() ; System.out.println("anyOf : " + anyOf.join()) ;
  • 63.
    #J8Async @JosePaumard Création surplusieurs tâchesCréation sur plusieurs tâches • Attention à la sémantique ! public static CompletableFuture<Void>  allOf(CompletableFuture<?>... cfs) ; CompletableFuture<Object> anyOf = CompletableFuture.anyOf() ; System.out.println("anyOf : " + anyOf.getNow("Nothing to say")) ;
  • 64.
    #J8Async @JosePaumard Gestion desexceptionsGestion des exceptions • Point délicat :  Une première étape consiste à créer les tâches et à décrire leur enchaînement  L’exécution des tâches démarre indépendamment des appels  À chaque étape, un CompletableFuture est créé
  • 65.
    #J8Async @JosePaumard Gestion desexceptionsGestion des exceptions • Un CompletableFuture peut dépendre :  Cas 1 : d’un autre CompletableFuture  Cas 2 : de deux autres CompletableFuture  Cas 3 : de N CompletableFuture
  • 66.
    #J8Async @JosePaumard Gestion desexceptionsGestion des exceptions • Une exception est jetée dans le cas 1  Tous les CompletableFuture sont en erreur • Ils se terminent « exceptionnellement »  isExceptionnaly() retourne true  L’appel à get() jette une ExecutionException  get().getCause() retourne l’exception première
  • 67.
    #J8Async @JosePaumard Gestion desexceptionsGestion des exceptions • Une exception est jetée dans le cas 2  Tous les CompletableFuture en aval sont en erreur • Ils se terminent « exceptionnellement » • L’autre tâche peut se terminer normalement  On peut l’interroger par get() pour avoir son résultat
  • 68.
    #J8Async @JosePaumard Gestion desexceptionsGestion des exceptions • Une exception est jetée dans le cas 3  Le CompletableFuture retourné est en erreur • Il se termine « exceptionnellement » • Les autres tâches peuvent se terminer normalement  On peut l’interroger par get() pour avoir son résultat
  • 69.
    #J8Async @JosePaumard Gestion desexceptionsGestion des exceptions • On peut aussi traiter une exception normalement  Dans ce cas, l’exception est passée à la fonction  Utile pour les checked exception CompletionStage<T> exceptionally( Function<Throwable, ? extends T> function);
  • 70.
    #J8Async @JosePaumard Gestion desexceptionsGestion des exceptions • Méthode whenComplete()  Dans ce cas t ou e est nul dans l’appel de action  Le CompletableFuture retourné peut ne pas être en erreur CompletionStage<T> whenComplete (BiConsumer<T, Throwable> action) ;
  • 71.
    #J8Async @JosePaumard Gestion desexceptionsGestion des exceptions • Méthode whenComplete() CompletionStage<T> whenComplete (BiConsumer<T, Throwable> action) ; CompletionStage<T> whenCompleteAsync (BiConsumer<T, Throwable> action) ; CompletionStage<T> whenCompleteAsync (BiConsumer<T, Throwable> action, Executor executor) ;
  • 72.
    #J8Async @JosePaumard Gestion desexceptionsGestion des exceptions • Méthode handle()  Dans ce cas t ou e est nul dans l’appel de function  Retourne un CompletableFuture qui peut ne pas être en erreur CompletionStage<T> handle (BiFunction<T, Throwable, U> function) ;
  • 73.
    #J8Async @JosePaumard Gestion desexceptionsGestion des exceptions • Méthode handle() CompletionStage<T> handle (BiFunction<T, Throwable, U> function) ; CompletionStage<T> handleAsync (BiFunction<T, Throwable, U> function) ; CompletionStage<T> handleAsync (BiFunction<T, Throwable, U> function, Executor executor) ;
  • 74.
    #J8Async @JosePaumard Une dernièreméthodeUne dernière méthode • CompletableFuture : On peut obtenir une estimation du nombre de tâches qui attendent l’exécution d’une tâche donnée int getNumberOfDependents() ;
  • 75.
    #J8Async @JosePaumard Exemple –1Exemple – 1 • Lecture asynchrone de liens et affichage CompletableFuture.supplyAsync( () ‐> readPage("http://whatever.com/") )
  • 76.
    #J8Async @JosePaumard Exemple –1Exemple – 1 • Lecture asynchrone de liens et affichage CompletableFuture.supplyAsync( () ‐> readPage("http://whatever.com/") ) .thenApply(page ‐> linkParser.getLinks(page))
  • 77.
    #J8Async @JosePaumard Exemple –1Exemple – 1 • Lecture asynchrone de liens et affichage CompletableFuture.supplyAsync( () ‐> readPage("http://whatever.com/") ) .thenApply(page ‐> linkParser.getLinks(page)) .thenAccept( links ‐> displayPanel.display(links) ) ;
  • 78.
    #J8Async @JosePaumard Exemple –1Exemple – 1 • Lecture asynchrone de liens et affichage CompletableFuture.supplyAsync( () ‐> readPage("http://whatever.com/") ) .thenApply(page ‐> linkParser.getLinks(page)) .thenAcceptAsync( links ‐> displayPanel.display(links), executor ) ;
  • 79.
    #J8Async @JosePaumard Exemple –1Exemple – 1 • Lecture asynchrone de liens et affichage public interface Executor { void execute(Runnable command); }
  • 80.
    #J8Async @JosePaumard Exemple –1Exemple – 1 • Lecture asynchrone de liens et affichage public interface Executor { void execute(Runnable command); } Executor executor = runnable ‐> SwingUtilities.invokeLater(runnable) ;
  • 81.
    #J8Async @JosePaumard Exemple –1Exemple – 1 • Lecture asynchrone de liens et affichage CompletableFuture.supplyAsync( () ‐> readPage("http://whatever.com/") ) .thenApply(page ‐> linkParser.getLinks(page)) .thenAcceptAsync( links ‐> displayPanel.display(links),  runnable ‐> SwingUtilities.invokeLater(runnable) ) ;
  • 82.
    #J8Async @JosePaumard Exemple –1Exemple – 1 • Lecture asynchrone de liens et affichage CompletableFuture.supplyAsync( () ‐> readPage("http://whatever.com/") ) .thenApply(Parser::getLinks) .thenAcceptAsync( DisplayPanel::display,  SwingUtilities::invokeLater ) ;
  • 83.
    #J8Async @JosePaumard Exemple –2Exemple – 2 • Événements asynchrones dans CDI @Inject Event<String> event ; event.fire("some event") ; // returns void public void observes(@Observes String payload) { // handle the event, called in the firing thread }
  • 84.
    #J8Async @JosePaumard Exemple –2Exemple – 2 • Événements asynchrones dans CDI public void observes(@Observes String payload) { // handle the event, called in the firing thread CompletableFuture.anyOf(/* some task */) ; }
  • 85.
    #J8Async @JosePaumard Exemple –2Exemple – 2 • Événements asynchrones dans CDI @Inject Event<String> event ; event.fireAsync("some event") ; // returns CompletableFuture<Object> (?) public void observes(@Observes String payload) { // handle the event in another thread }
  • 86.
    #J8Async @JosePaumard Exemple –2Exemple – 2 • Événements asynchrones dans CDI @Inject Event<String> event ; event.fireAsync("some event", executor) ;  public void observes(@Observes String payload) { // handle the event in the executor }
  • 87.
    #J8Async @JosePaumard Exemple –2Exemple – 2 • Événements asynchrones dans CDI @Inject Event<String> event ; event.fireAsync("some event", executor) ;  @Produces @SwingExecutor Executor executor = SwingUtilities::invokeLater public void observes(@Observes String payload,  @SwingExecutor Executor executor) { // handle the event in the Swing thread }
  • 88.
    #J8Async @JosePaumard Exemple –2Exemple – 2 • Événements asynchrones dans CDI @Inject Event<String> event ; event.fireAsync("some event", executor) ;  @Produces @SwingExecutor Executor executor = SwingUtilities::invokeLater public void observes(@Observes @SwingExecutor String payload) { // handle the event in the Swing thread }
  • 89.
    #J8Async @JosePaumard Exemple –3Exemple – 3 CompletableFuture<String> closing = new CompletableFuture<String>() ; Stream<String> manyStrings = Stream.of("one", "two", "three") ; CompletableFuture<String> reduce = manyStrings .onClose(() ‐> { closing.complete("Closed") ; }) .map(CompletableFuture::completedFuture) .reduce( closing,   (cf1, cf2) ‐> cf1.thenCombine(cf2, function) // concatenation ) ; manyStrings.close() ;
  • 90.
    #J8Async @JosePaumard L’indispensable !L’indispensable! • Fixer la taille du Common Fork / Join Pool System.setProperty( "java.util.concurrent.ForkJoinPool.common.parallelism", 2) ;
  • 91.
    #J8Async @JosePaumard ConclusionConclusion • Ona une API pour le calcul asynchrone dans le JDK !
  • 92.
    #J8Async @JosePaumard ConclusionConclusion • Ona une API pour le calcul asynchrone dans le JDK ! • Très riche et souple à l’utilisation
  • 93.
    #J8Async @JosePaumard ConclusionConclusion • Ona une API pour le calcul asynchrone dans le JDK ! • Très riche et souple à l’utilisation • Construite sur l’utilisation des lambda
  • 94.
    #J8Async @JosePaumard ConclusionConclusion • Ona une API pour le calcul asynchrone dans le JDK ! • Très riche et souple à l’utilisation • Construite sur l’utilisation des lambda • Permet un contrôle fin des threads
  • 95.
    #J8Async @JosePaumard ConclusionConclusion • Ona une API pour le calcul asynchrone dans le JDK ! • Très riche et souple à l’utilisation • Construite sur l’utilisation des lambda • Permet un contrôle fin des threads • Gère différents types de chaînage
  • 96.
    #J8Async @JosePaumard ConclusionConclusion • Ona une API pour le calcul asynchrone dans le JDK ! • Très riche et souple à l’utilisation • Construite sur l’utilisation des lambda • Permet un contrôle fin des threads • Gère différents types de chaînage • Gère intelligemment les exceptions
  • 97.
  • 98.