ExecutorService vs CompletableFuture

Functionally, the two approaches are more or less the same:

  • you submit your tasks for execution;
  • you don’t wait for the result.

Technically, however, there are some subtle differences:

  • In the second approach, you didn’t specify an executor, so it will use the common ForkJoinPool. You would have to pass an executor as second argument of supplyAsync() if you don’t want that;
  • The CompletableFuture API allows to easily chain more calls with thenApply(), thenCompose() etc. It is thus more flexible than the simple Future returned by ExecutorService.submit();
  • Using CompletableFuture allows to easily return a future from your child() method using return CompletableFuture.allOf(the previously created futures).

Concerning readability, it’s a matter of preference, but if you want equivalent code the CompletableFuture approach might be considered a bit less readable once you have formatted it similarly. Compare:

executorService.submit(MyFileService::service1);
executorService.submit(MyFileService::service2);
executorService.submit(MyFileService::service3);

with

CompletableFuture.supplyAsync(MyFileService::service1, executorService);
CompletableFuture.supplyAsync(MyFileService::service2, executorService);
CompletableFuture.supplyAsync(MyFileService::service3, executorService);

Leave a Comment

Hata!: SQLSTATE[08004] [1040] Too many connections