0

Java 8's promise implementation, namely CompletableFuture, provides both thenApply(...) and get() methods.

Where get() waits if necessary for the promise to complete, and then returns its result.


Now assume we use thenApply(...) (or thenApplyAsync(...)) to chain some code to run on UI-thread
(see stackoverflow.com/difference between thenApply and thenApplyAsync).

What is the behaviour if we call get() in the UI-thread as well, like does Java handle this case somehow, or can it result to a so-called dead-lock or infinite-loop?


I previously was using Qt framework, where depending on how we did implement waiter (dispatch-UI-events vs sleep), it was possible to wait for UI-thread from within same UI-thread (for example, the entire view came back to live, and that without returning from my code).
But I am not sure if Java even supports that.

Top-Master
  • 7,611
  • 5
  • 39
  • 71
  • How do you chain the `thenApply` to [run on UI thread](https://stackoverflow.com/q/60745016/2541560)? If you're calling `get()` in UI thread and it's not completed, then your UI will freeze. Instead of making the UI wait for it to complete, I'd consider `thenAccept()` callback that will update any data the UI needs. – Kayaman May 26 '22 at 11:02
  • @Kayaman any UI changes should be made on the event dispatcher thread. As I've said in my answer, using `thenAcceptAsync` in combination with `EventQueue::invokeLater` should solve that. – Rob Spoor May 26 '22 at 11:07
  • @RobSpoor yes, but you can change the model and let the EDT update itself based on that instead of explicitly scheduling which threads things run on. If he's trying to manually handle things and schedule futures, it's gonna become an unmaintainable piece of crap. – Kayaman May 26 '22 at 11:23
  • Every change, including that to the UI's models, should be done on the EDT. That means implicitly or explicitly using `EventQueue.invokeLater`. Letting the `CompletableFuture` do that for you will make things easier, not harder. If any intermediate updates are required then perhaps `CompletableFuture` is not the best tool but instead a `SwingWorker`. – Rob Spoor May 26 '22 at 11:28

1 Answers1

3

Calling get() blocks the current thread until the result is available. If that's the UI event dispatcher thread then your application's UI becomes unresponsive (blocked).

And unlike Qt, Java does not support manually processing the UI events, meaning once you wait on the UI-thread nothing else can run on UI-thread (until waiter returns).


In addition, don't hack "thenApply(...)" method to run things on UI-thread, as there's a better solution, I mean use the thenApplyAsync(...) version which takes an Executor as parameter. Said Executor is a functional interface with one method, void execute(Runnable command). You can use EventQueue::invokeLater (or its wrapper SwingUtilities.invokeLater) for that. It will then execute the code on the event dispatcher thread (aka UI-thread).

Top-Master
  • 7,611
  • 5
  • 39
  • 71
Rob Spoor
  • 6,186
  • 1
  • 19
  • 20
  • 1
    Any action on the EDT (so the UI thread) causes all user input and screen drawing to be suspended until the action is finished. That's why any code that needs to be executed on the EDT should be finished as soon as possible. Anything that would cause noticeable delays should be done in a different thread, e.g. using a `SwingWorker`. The EDT (event dispatcher thread) will not finish until the UI is completely shut down. – Rob Spoor May 26 '22 at 17:21
  • 1
    Basically correct. But you can use [`createSecondaryLoop()`](https://docs.oracle.com/en/java/javase/17/docs/api/java.desktop/java/awt/EventQueue.html#createSecondaryLoop()) to process events until an application specific criteria. But you should be careful with it; when you start a new event loop in the middle of an event delivery, e.g. from your listener, you may process new events while there might be other listeners still not notified about the current event. Though that’s not new. A similar problem can arise with modal dialogs opened from a listener. – Holger May 30 '22 at 08:08