Enqueue method locks on get()

Future<V> enq = jmeApp.enqueue(() -> function.apply(jmeApp));

enq.get(); //code is locked forever

I’m using JME <jme3.version>3.0.10</jme3.version> from the MVN Repo.

Is there a solution for that problem ?

Can you please explain what are you trying to do and what’s your objective?

Hi,

Thank you for being so quick :smile:

I use JME with JavaFX, I need to communicate between JFX / JME Threads. I use the "enqueue" method to do so.

So I wrote a test:

Future<Boolean> fut = jmeApp.enqueue(() -> { print("Test"); true; });

Then I just did:

fut.get();

Which is supposed to return true but never ends. The .get() method locks, in other words I can’t get the result.

However, the word "Test" is printed, it means that it has been well executed.

I think the problem is coming from JME, I dont know if it has already been fixed. The updates are never pushed on the MVN Repo.

Thanks.

LOL. No. The problem comes from your thread understanding or your understanding of the enqueue() method.

get() blocks until the enqueued task has completed. So… for example, if you enqueue it from the render thread and then call get() it will never return because you are blocking the render thread… which is where it will eventually run.

First, I STRONGLY DISCOURAGE YOU from using get(). Tell us what you are really trying to do and we will provide alternatives. get() should only be used by someone with deep knowledge of rthreading.

Second, if you must use get() (and note: I have personally never used future.get() in my entire Java career) then you should check to see if it’s ready before calling get().
https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Future.html#isDone()

Else, it is behaving exactly as it is supposed to and only your expectations are incorrect.

Use of this is discouraged because it can lead to deadlocks unless you understand what you are doing. (Exactly as you’ve done now but even with multiple threads it can happen if thread1 calls get waiting for thread2 but thread2 is also calling get() waiting for thread1.)

Better to design a fully asynchronous approach to your problem.

Which is why I always use ListenableFuture/AsyncFuture in preference of normal java Future whenever possible. Gives you a choice of asynchronous or synchronous handling from same API.

As for never calling .get()… I do that sometimes. For example, when you have mostly serial piece of code, but certain bit inside is parallelizable - then I fire off parallelizable tasks into multi-threaded executor and then call .get() on all returned futures from main thread. Same can be achieved with CountDownLatch, but sometimes futures are easier.

This has happened even in JME3 code. I found out that I can do a lot of preprocessing for light/shadow handling in parallel. Still has to be done in specific moment of rendering thread, so I had to block till last bit of data is available, but computation can run in parallel.
That’s the theory, because in the process I have found out that Camera.intersects(BoundingVolume) is mutating BoundingVolume (and processing was done per-camera) … and that something very strange is happening with my CPU and even without any synchronization involved, some memory math operations are a lot slower when more than one thread does them. Might be related to cache behaviour on AMD processors, could not be bothered to really got deep into that.

Yes, but presumably you have the experience to know the risks.

I hope you aren’t one of the folks who thinks it’s ok to access data structures unprotected from multiple threads because “I’m only reading from them”… because that’s dangerous.

Nope, I know about read and write memory barriers, but in this case it would work, assuming methods not modifying state. Scheduling execution is a memory synchronization, same for getting new task for execution in executor thread. It is not that easy to mess up read-only access if you are using executors in most obvious way, most people get burned when they try to optimize things (and do too many things from same runnable, without returning to executor for sync point). But given suprising performance degradation (in method itself, I was measuring it inside runnable, so it was not overhead of executor) and requirement to rewrite all the methods externally in stateless versions, I gave up for now - I’m far from the point where I really need to optimize things at that level.

You might take a look at the jme inside javafx section, inside the [jme-jfx] (JME3-JFX/src/main/java/com/jme3x/jfx/injfx at master · empirephoenix/JME3-JFX · GitHub) framework.

It uses the enqueue pattern and it works very well. But of course, you would better know what you are doing with enqueue because it may become complex.

I’m a big user of enqueue(…) I guess in all my jme’s project, sample, lib. I used it:

  • instead of initialize from SimpleApplication
  • to update Scenegraph or AppStateManager from other Thread (AWT, JavaFX, network, RxJava)

But I don’t remember to use it to retreive data, I guess if enqueue was enqueue(Runnable) it will cover 90% of my needs.

Java’s Future are less usefull Future API I saw (no then(…), map(…), recover(…), …) like in other Language (Scala/Akka, javascript/Q, Dart,…). IIRC ListenableFuture from guava is more usable for Async dev in Java. Java’s Future is only usable to test if it’s fullfilled or not.

Idem, I’ve created an overloaded enqueue that accept a consumer :slight_smile:

But I’ve never used Future. I should test.

Thank you, I’m gonna take a look at Google Guava ListenableFuture/AsyncFuture.

I solved my problem by synchronizing the JME rendering thread with JavaFX with simple ReentrantLocks.

Avoid lock as much as possible. try something like:

  • from JavaFX → jme : use jmeApp.enqueue(…)
  • from jme → JavaFX: use Platform.runLater(…)

ex: