6

I have a javaFX application which visualizes compuational geometry algorithms. The execution of an algorithm happens in another thread, lets call it mainComputingThread. An algorithm can update the UI at any time by adding/removing/modifying shapes. so the code will look like:

//do some computaions (1)
updateUI();
//do some more calculations (2)

What I want know is in the updateUI method to update the UI immediately and prevent the calling thread from running further (marked as (2)) until the UI update is done.

I thought about boolean guards. So the code could would look like:

updateUI(){
   boolean guard = false;
   Platform.runLater(new Runnable()
   {
      run(){
        //do the actual update
        guard = true;
      }
   });
   while(guard==false);
}

I hope you get an idea of what I mean. I'm really curious if there's a better solution for this problem...

Tom Jonckheere
  • 1,630
  • 3
  • 20
  • 37
Manuel Jain
  • 751
  • 1
  • 6
  • 16
  • Is the thread (algorithm), running indefinitely, in your program? – ItachiUchiha Jun 01 '15 at 09:35
  • yes, the basic idea is, that you can attach different algorithms and run them. so i don't know anything about the algorithm itself – Manuel Jain Jun 01 '15 at 10:17
  • Your code won't actually compile, because lambda expressions can only access "effectively final" local variables. Moreover, you have "liveness" issues with `guard`: there's no actual guarantee your background thread would ever see the changes made to `guard` on the UI thread. You should use an [`AtomicBoolean`](http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/atomic/AtomicBoolean.html) if you want to do it this way, or use higher-level concurrency APIs (see my answer). – James_D Jun 01 '15 at 11:16
  • for sure it won't compile. i just added this code to formalize my thoughts – Manuel Jain Jun 01 '15 at 14:15

3 Answers3

9

Simple approach: block background thread until update is complete:

You need to update the UI on the FX Application Thread. Typically you do this by passing a plain Runnable to Platform.runLater(...).

If you want to wait for that ui update to complete before proceeding, instead create a FutureTask and pass it to Platform.runLater(...). Then you can call get() on the FutureTask, which will block until the task is complete:

private void updateUI() throws InterruptedException {

    // actual work to update UI:
    FutureTask<Void> updateUITask = new FutureTask(() -> {

        // code to update UI...

    }, /* return value from task: */ null);

    // submit for execution on FX Application Thread:
    Platform.runLater(updateUITask);

    // block until work complete:
    updateUITask.get();
}

This lets the FutureTask handle all the tricky work of waiting and notifying: it is always better to use a higher-level API for this kind of work when you can.

If you like, you can refactor this into a utility method, similarly to Dainesch's answer:

public class FXUtils {

    public static void runAndWait(Runnable run) throws InterruptedException {
        FutureTask<Void> task = new FutureTask<>(run, null);
        Platform.runLater(task);
        task.get();
    }
}

Alternative approach: ensure that no more than one update is consumed during any frame rendering, blocking the background thread if an update is pending

Here is a somewhat different approach. Create a BlockingQueue with a capacity of 1 to hold the Runnables that update the UI. From your background thread, submit the Runnables to the blocking queue: since the blocking queue can hold at most one element, this will block if one is already pending.

To actually execute the updates in the queue (and remove them, so more can be added), use an AnimationTimer. This looks like:

private final BlockingQueue<Runnable> updateQueue = new ArrayBlockingQueue<>(1);

background thread code:

// do some computations...

// this will block while there are other updates pending:    
updateQueue.put(() -> {
    // code to update UI
    // note this does not need to be explicitly executed on the FX application
    // thread (no Platform.runLater()). The animation timer will take care of that
});

// do some more computations

Create the timer to consume the updates:

AnimationTimer updateTimer = new AnimationTimer() {

    @Override
    public void handle(long timestamp) {
        Runnable update = updateQueue.poll();
        if (update != null) {
            // note we are already on the FX Application Thread:
            update.run();
        }
    }
};

updateTimer.start();

This basically ensures that no more than one update is ever scheduled at any time, with the background thread blocking until any pending updates are consumed. The animation timer checks (without blocking) for pending updates on each frame rendering, ensuring that every update is executed. The nice thing about this approach is that you can increase the size of the blocking queue, effectively keeping a buffer of pending updates, while still ensuring no more than one update is consumed during any single frame rendering. This might be useful if there are occasional computations that take longer than others; it gives these computations a chance to be calculated while others are waiting to be executed.

James_D
  • 201,275
  • 16
  • 291
  • 322
  • i really like the approach with the ActionTimer. But one Question regarding the underlying BlockedQueue. When i poll the runnable, will the block be released instantly or after the runnable is executed? – Manuel Jain Jun 01 '15 at 14:34
  • The block will be released on exiting the `poll()` method, so the background thread will be able to start the next computation. Of course, you won't process any more computation results until the next frame (the next time `handle(...)` is invoked). – James_D Jun 01 '15 at 14:37
  • If you want it only to release the block after executing the update (though I can't see a valid reason you would want this), then replace the call to `poll()` with a call to `peek()`, and call `poll()` immediately after `update.run()` (discarding the result). – James_D Jun 01 '15 at 14:44
  • you're right, there is no reason for that...just didn't had in my mind anymore, that the computation will be blocked on the next upodateUI call anyways – Manuel Jain Jun 01 '15 at 17:11
  • sorry not working ,am getting java.lang.nullpointerException in my javafx main Thread – guru_001 Sep 04 '16 at 10:04
  • @guru_001 If you don't know how to fix a null pointer exception, read [this question](http://stackoverflow.com/questions/218384/what-is-a-nullpointerexception-and-how-do-i-fix-it). That has nothing to do with what is discussed here. – James_D Sep 04 '16 at 13:27
2

Hard question to answer without having the reason why you want to stop processing before the UI update is done. (Note: the runLater method executes the UI updates in the order received) Is it to prevent spamming to many Runnables to the JavaFX thread? Other reasons?

Your basic idea however works with the use of a CountDownLatch so that the processing thread waits to acquire a permit. If you choose that approach use something like this:

public class MyFXUtils {

    public static runAndWait(final Runnable run) {
        final CountDownLatch doneLatch = new CountDownLatch(1);
        Platform.runLater(new Runnable() {
            public void run() {
                 try {
                     run.run();
                 } finally {
                     doneLatch.countDown();
                 }
            }
        });
        doneLatch.await();
    }
}

EDIT: replaced Semaphore by CountDownLatch

Dainesch
  • 1,320
  • 13
  • 19
  • 1
    I may be wrong, but if the background thread aquires the semaphore before the runnable, this won't wait. I think that's possible (even likely). – James_D Jun 01 '15 at 11:56
1

EDIT:

So, the quickest way I always do it in prototypes is as following, transform:

//do some computaions (1)
updateUI();
//do some more calculations (2)

into

ExecutorService executor = Executors.newFixedThreadPool(1);
class JobStep implements Runnable {

  public void run() {
     doSomeComputations();
     Platform.runLater(() -> {
        updateUI();
        executor.submit(new JobStep());
     });
  }
executor.submit(new JobStep());

OLD PART

Not an answer, but a suggestion how to attack the problem.

From my experience, the complete solution would be much more elaborate. I would separate the JavaFX shape instances from the shapes, which your algorithm does process. I would do it by means of using different class types and synchronize between the two.

The graphical algorithms have the tendency to be a lot quicker than the ones that are visualizing it. If the algorithm runs on small data set, then the rendering most often tend to slow down it significantly. It can easily be seen by running the same algorithm with and without visualization.

If the data set is bigger than the most trivial ones, then drawing of a single frame can easily take more than one second. Interactive visualizations are expected to respond in "real time", preferably many times per second.

The data visualization facilities have many means to tackle the problem. The best candidates always include:

  1. Simplifying visualization. Drawing simpler shapes instead of complex, like removing the rounding from boxes. The LOD (level of detail) also applies to this point: during interactive scroll the visualized elements might be replaced by bounding box counterparts.

  2. Selective hiding. Drawing only a part of the whole data set.

  3. Parallelizing and hardware acceleration. The GPU's natively provide many means to handle complex visualizations. Typically the low level programming APIs (OpenGL, shader programs) allow much better throughput than every high level wrapping API, including JavaFX

Most often, the end solutions incorporate not only above points, but also others, including domain specific optimizations.

The visualization facilities always come with a lot of restrictions, like the most common one: have to be updated in the dedicated thread (thread confinement approach). They also come with visualization specific data structures.

From the data processing algorithm stage, one of the most common requirements is that it cannot be blocked or delayed by visualization. The algorithms are also written in a style, which doesn't translate to well for the means of visualization: imperative loops over data structures instead of updating observable drawable objects. There is a good reason to it though: the algorithms are expected to be optimized for performance or memory consumption.

One architectural approach to the problem might be as following:

  1. The data processing stage produces snapshots at predefined points. The adding, modifying and remove operations are all published as this packet. It can be a just a copy of data structure that is being processed or it can be in the form of the coalesced events.

  2. The data processing and data visualization run on different threads. They communicate only by means of publishing snapshots, never by blocking each other directly.

  3. The snapshots shouldn't be restricted to particular frame rate. There should be means to batch updates before drawing or drawing same batch multiple times if the data processing stage stalls.

I strongly recommend reactive approach to the problem. The RxJava provides nice example for the "suggestion box" feature. It's very good at correctly handling requirements like "Every key update do a long running process on different thread and discard the last one, if any was running. Or maybe, don't do it on every key update, but wait 50ms for the user to make up his mind before he ends typing".

Rekin
  • 9,731
  • 2
  • 24
  • 38
  • performance is not an issue here. of course i will massively increase the runningTime for a certain algorithm by perfoming the UI updates. but as this project is mainly for demonstarting the work of an algorithm "step by step", it doesn't matter. so a clear UI update is the key wish – Manuel Jain Jun 01 '15 at 09:54
  • Alright, then something else might work a lot better: implement the algorithm directly on observable objects, which synchronously update the drawing. – Rekin Jun 01 '15 at 09:57
  • I'm adding an edit, how I build such prototypes in Swing – Rekin Jun 01 '15 at 09:58
  • thats sounds good, thanks a lot. regarding my initial approach in the question: does someone see any problems with it? – Manuel Jain Jun 01 '15 at 09:59