7 votes

Est-ce que tous les futurs passés à CompletableFuture.allOf() s'exécutent ?

J'ai donc quelques projets futurs que je veux mener à bien, même si certains échouent, j'aimerais que tous aient une chance de se réaliser. Donc si je le fais :

CompletableFuture.allOf(futures).join()

Est-ce que ce sera le cas ? Mon raisonnement est le suivant : chaque futur aura son propre travail en file d'attente dans son exécuteur et, par conséquent, tous s'exécuteront si le fil principal ne se termine pas en premier. Mon problème est que j'ai spécifiquement .join() en .allOf() pour que mon application ne se termine pas avant d'avoir tout exécuté

Así que allOf() La sémantique m'embrouille : Le retour du futur sera-t-il complet lorsque tous les futurs passés seront complets, qu'ils aient réussi ou non ? Ou est-ce que le futur sera complet s'il voit un échec sans attendre les autres ?

EDIT

Pour illustrer davantage ma question, est-ce que .allOf se comporte ainsi :

Stream.of(futures).forEach(future -> {
  try {
    future.join()
  } catch (Throwable e) {
    //dont throw, we want to join the rest
  }
})

Ou bien se comporte-t-il comme suit :

Stream.of(futures).forEach(future -> {
  try {
    future.join()
  } catch (Throwable e) {
    throw e; //All other remaining .join() wont run
  }
})

Lequel est-ce ? Le premier ou le second cas ? Puisque je veux le premier cas, c'est ce que j'utilise temporairement dans mon code, mais je voudrais utiliser allOf() si possible parce que c'est plus esthétique

Merci !

4voto

Deepak Points 1037

Oui, chaque avenir sera tenté indépendamment pour être achevé.

Je pense que vous essayez également de comprendre comment le contrôle circule dans différents scénarios. J'ai imaginé 4 scénarios :

  1. Un futur où l'échec se produira à cause d'une exception non gérée.
  2. Un futur qui est explicitement marqué comme ayant échoué avec un completeExceptionally ET a un bloc exceptionnellement à sa queue.
  3. Un futur qui est explicitement marqué comme ayant échoué avec un completeExceptionally ET qui n'a pas de bloc exceptionnel à sa queue.
  4. Un avenir qui s'achève sur un succès.

    //CASE 1 // A future that shall fail due to an unandled exception in its run // and has an exceptionally block at its tail CompletableFuture<Void> unhandledFailureFutureWithExceptionHandler = CompletableFuture.runAsync(() -> { throw new RuntimeException("Exception in unhandledFailureFutureWithExceptionHandler"); }); unhandledFailureFutureWithExceptionHandler = unhandledFailureFutureWithExceptionHandler .exceptionally(throwable -> { // Handling exception for this future // HANDLING POINT 1 System.out.println("Handling exception at HANDLING POINT FOR CASE 1, failure message is : " + throwable.getMessage()); return null; });

    //CASE 2 //A future that shall fail and has an exceptionally block at its tail CompletableFuture<Void> failedFutureWithExceptionHandler = new CompletableFuture<>(); failedFutureWithExceptionHandler.completeExceptionally( new RuntimeException("Exception in failedFutureWithExceptionHandler") ); failedFutureWithExceptionHandler = failedFutureWithExceptionHandler.exceptionally(throwable -> { // Handling exception for this future // HANDLING POINT 2 System.out.println("Handling exception at HANDLING POINT FOR CASE 2, failure message is : " + throwable.getMessage()); return null; });

    //CASE 3 //A future that shall fail and has no exceptionally block at its tail CompletableFuture<Void> failedFutureWithoutExceptionHandler = new CompletableFuture<>(); failedFutureWithoutExceptionHandler.completeExceptionally( new RuntimeException("Exception in failedFutureWithoutExceptionHandler") );

    //CASE 4 //A future that shall succeed and print a message to console CompletableFuture<Void> successFuture = CompletableFuture.runAsync(() -> System.out.println("CASE 4 : Running successFuture") );

    CompletableFuture.allOf(unhandledFailureFutureWithExceptionHandler, failedFutureWithExceptionHandler, failedFutureWithoutExceptionHandler, successFuture) .exceptionally(throwable -> { // Handling exception if ANY of the futures that did not have its own exceptionally block // In this case the exception of failedFutureWithoutExceptionHandler will be handled here // HANDLING POINT 3 System.out.println("Handling exception at HANDLING POINT FOR CASE 3, failure message is : " + throwable.getMessage()); return null; }).join();

La sortie produite sur la console est

Handling exception at HANDLING POINT FOR CASE 1, failure message is : java.lang.RuntimeException: Exception in unhandledFailureFutureWithExceptionHandler
Handling exception at HANDLING POINT FOR CASE 2, failure message is : Exception in failedFutureWithExceptionHandler
CASE 4 : Running successFuture
Handling exception at HANDLING POINT FOR CASE 3, failure message is : java.lang.RuntimeException: Exception in failedFutureWithoutExceptionHandler

Comme vous pouvez le constater, si un futur génère une erreur non gérée, comme dans le cas 1, s'il a un fichier exceptionally enchaîné à sa queue, l'exception sera traitée à ce moment-là

Comme pour le cas 2, dans le cas où le futur est marqué comme échoué avec completeExceptionally si le futur a un gestionnaire enchaîné à sa queue, alors la fonction exceptionally sera traité par ce bloc

Dans le cas 3, le futur est marqué comme échoué et n'a pas de bloc d'exception, il sera donc traité par la fonction exceptionally au niveau suivant, dans ce cas, il s'agit du bloc exceptionally du bloc allOf() .

Comme vous pouvez le voir, le cas 4 s'exécute jusqu'au bout et le message s'affiche sur la console, indépendamment des échecs des autres futurs.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X