10. #J8Async @JosePaumard
• 3ème façon de faire :
• Plus rapide ?
En général oui
Approche « non blocking »
AsynchroneAsynchrone
11. #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
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 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
17. #J8Async @JosePaumard
Notion de tâcheNotion de tâche
• Pattern
Callable<String> task = () ‐> "select user from User" ;
Future<String> future = executorService.submit(task) ;
18. #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) ;
19. #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) ;
27. #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.
*/
28. #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
*/
29. #J8Async @JosePaumard
• Classe d’implémentation : CompletableFuture
• Implémente à la fois :
Future
CompletionStage
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 ?
38. #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
39. #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
40. #J8Async @JosePaumard
Création d’un CompletableFutureCréation d’un CompletableFuture
• CompletableFuture déjà terminé
public static <U> CompletableFuture<U> completedFuture(U value) ;
41. #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) ;
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) ;
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
59. #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) ;
60. #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) ;
61. #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()) ;
62. #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()) ;
63. #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")) ;
64. #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éé
65. #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
66. #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
67. #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
68. #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
69. #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);
70. #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) ;
72. #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) ;
74. #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() ;
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
}
94. #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
95. #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
96. #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