1

I have a bunch of methods using Phaser (with always 1 party) and I could replace each method by using CompletableFuture instead. The result would be the same. Are there any hidden benefits when using CompletableFuture?

For example:

version 1 with CompletableFuture:

void queryVersion1() {
    var future = new CompletableFuture<Void>();
    asyncCall(future);
    future.join();
}

void asyncCall(CompletableFuture<Void> future){
    ...
    future.complete(null);
}

version 2 with Phaser:

void queryVersion2() {
    var phaser = new Phaser(1);
    asyncCall(phaser);
    phaser.awaitAdvance(0);
}

void asyncCall(Phaser phaser){
    ...
   phaser.arriveAndDeregister();
}

Which one should I prefer and why? Which one performs better in terms of memory/thread pool/etc.

nimo23
  • 5,170
  • 10
  • 46
  • 75
  • Readability? Though I don't know what the two versions of your code look like as you don't provide an example. – Slaw Feb 23 '20 at 13:36
  • No in my case, both have good readability. I mean difference in terms of performance (object creation overhead, synchronization overhead,..). I think phaser is more lightweight than CompletableFeature, the same as CoundDownLatch is more lightweight than CompletableFuture, or? – nimo23 Feb 23 '20 at 13:55
  • Could you show an example of using both? I would expect `Phaser` to be blocking while `CompletableFuture` may not be. But I don't have much experience with `Phaser` so I'm not sure how you might be using it. – Slaw Feb 23 '20 at 15:05
  • @Slaw yes, phaser will block and I actually have one problem when replacing my phaser code with CompletableFuture (https://stackoverflow.com/questions/60363317/completablefuture-and-thread-currentthread-interrupt): The calls of two CompletableFuture methods seem not be isolated from each other. With phaser I do not have such troubles. So I stick to phaser. – nimo23 Feb 23 '20 at 15:11
  • Maybe one difference, but I am not sure: CompletableFuture uses default ExecutorService (also for blocking code) while CoundDownLatch/Phaser does not need an ExecutorService behind, or? – nimo23 Feb 23 '20 at 20:00
  • I think the executor of CompletableFuture is only used for Async calls, but not for blocking calls.. – nimo23 Feb 23 '20 at 23:13
  • It's a little more nuanced than that. I recommend reading the class documentation of [`CompletionStage`](https://docs.oracle.com/en/java/javase/13/docs/api/java.base/java/util/concurrent/CompletionStage.html) and [`CompletableFuture`](https://docs.oracle.com/en/java/javase/13/docs/api/java.base/java/util/concurrent/CompletableFuture.html) to understand more about how stages are triggered and what threads are used. But methods like `CompletableFuture#join()` and `CompletableFuture#get()` will block the _calling_ thread. – Slaw Feb 23 '20 at 23:47
  • I only use `CompletableFuture#join()`, `CompletableFuture#complete()` and `CompletableFuture#completeOnTimeout` to replace the phasers. So only the latter makes use of CompletableFuture's executor service. – nimo23 Feb 24 '20 at 08:18
  • Be careful about how you use the `orTimeout` and `completeOnTimeout` methods. If the time elapses then the next stage will be invoked on the thread used to implement timeouts. – Slaw Feb 24 '20 at 12:10
  • @Slaw I updated the question with an example. Maybe you can look or know about the subtle differences between the two versions.. – nimo23 Feb 25 '20 at 13:14
  • 1
    In my opinion, the design of your code, or at least the example you provide, indicates using `Phaser` would be more appropriate. Use `CompletableFuture` if you want to chain different actions together based on the result of the previous action in an asynchronous manner. That said, `Phaser` would seem to be designed for something more sophisticated than your example suggests. Why not use `CountDownLatch`? – Slaw Feb 25 '20 at 20:07
  • Thanks. `CoundDownLatch` would require to handle it within try..catch..clause..`Phaser` is less code in compare to `CountDownLatch`. – nimo23 Feb 25 '20 at 20:22
  • However, one benefit of CompletableFuture is that I can set the return type directly within .complete() so if I want to return a value, then CompletableFuture is less code in compare to Phaser. I run a benchmark and I cannot see any speed differences between using Phaser or CompletableFuture..so I think, there is no difference when it comes to speed performance. However, I think for blocking code, Phaser and CoundDownLatch is more appropriate and lightweight than CompletableFuture. – nimo23 Feb 25 '20 at 20:26

0 Answers0