4

Nowadays some says it is not suitable to use Platform.runLater() for updating the UI from a non-JavaFX Thread and Oracle site introduce a way with bindings for progress bar updating. Here I want to update a Label, so coded it like this:

Task task = new Task() {
    @Override
    protected Object call() throws Exception {
        int i = 0;
        while (true) {
            this.updateMessage("Count " + i);
            System.out.println(i);
            // Thread.sleep(10);
            i++;
        }
    }
};

Thread t = new Thread(task);
lbStatus.textProperty().bind(task.messageProperty());
t.start();

It works.

I want to know is it good enough or is there any other ways to consider? Thank you.

Andrii Abramov
  • 10,019
  • 9
  • 74
  • 96
Lalith J.
  • 1,391
  • 4
  • 16
  • 27
  • possible duplicate of [Java fx running on UI alternatives](http://stackoverflow.com/questions/27113633/java-fx-running-on-ui-alternatives) – javaHunter Dec 05 '14 at 09:47

2 Answers2

3

I don't think it's quite true to say it's not "suitable" to use Platform.runLater(...) to update the UI from a background thread. There are certainly cases where that is the correct thing to do, as shown in the Task Javadocs. What the javafx.concurrent API provides is a "higher-level" interface to the functionality you commonly need when you are writing multithreaded JavaFX applications. The classes in this package are written by people with a lot of expertise in multithreaded programming, so it's likely that they have accounted for subtleties that the average programmer may not be aware of.

As an example, while it is correct that updateMessage eventually ends up calling Platform.runLater(...), the two are not completely equivalent. If you try the same thing with a naïve call to Platform.runLater(..):

// Don't do this! It will make the UI unresponsive:
Task task = new Task() {
    @Override
    protected Object call() throws Exception {
        int i = 0;
        while (true) {
            Platform.runLater(() -> lblStatus.textProperty().set("Count "+i));
            i++;
        }
        return null ;
    }
};
Thread t = new Thread(task);

your UI will become (at least partially) unresponsive. The reason is that you're scheduling so many Runnables on the FX Application thread, it doesn't have time to do its regular work (rendering UI, responding to user input, etc). The implementation of updateMessage(...) is carefully written to "throttle" the calls to Platform.runLater(...) (it basically limits them to one per frame-rendering). That code is a little tricky to implement: using the javafx.concurrent API as in your code example means you don't have to implement it yourself.

So changes to the UI must always be made on the FX Application Thread, and the way to schedule those changes is via Platform.runLater(...). In effect you either call that directly, or call code that ends up calling it. However, some of the API methods that wrap the calls to Platform.runLater(...) do so in quite sophisticated ways, and when those methods provide the functionality you need, you should probably prefer those to making the calls yourself.

James_D
  • 201,275
  • 16
  • 291
  • 322
  • Thanks for the reply. Yes you are right. direct calls to Platform.runLater() stuck the UI. "some of the API methods that wrap the calls to Platform.runLater(...)". Do you mean methods like updateMessage() ? Talking of this particulate code, Is this good enough or is there other ways to consider? – Lalith J. Dec 05 '14 at 17:56
  • 1
    Yes, the `update*(...)` methods in particular throttle calls to the UI; it is basically safe to call those methods as often as you like. – James_D Dec 05 '14 at 18:21
  • Also see http://stackoverflow.com/questions/23488280/throttling-javafx-gui-updates – James_D Dec 05 '14 at 18:40
0

As updateMessage() on a Task finally uses Platform.runLater() to update the messageProperty, it is no alternative to a direct runLater() in your code. So the essence is:

JavaFX is not multithreaded, any Porperty binding will only work if the property is modified in the JavaFX thread, e.g. by using Platform.runLater().

Jens-Peter Haack
  • 1,887
  • 13
  • 18
  • Thank you for the reply. Okay, but when we use direct platform.runlater() it cause to hang the UI completely , when we use updateMessage() with some bindings it is working fine. may be that's why oracle using bindings for their Concurrency demonstration too. https://docs.oracle.com/javafx/2/threads/jfxpub-threads.htm. The question is ... I want to know that is this good enough or is there other ways to consider? – Lalith J. Dec 05 '14 at 17:50
  • When does the system hang, if you call Platform.runLater() in the example above, without calling Thread.sleep() in the loop? That will hang due to: causing an overload of queued 'runLater()' tasks! – Jens-Peter Haack Dec 05 '14 at 17:57
  • Yes without calling Thread.sleep(). When use bindings and updateMessage() it is not hanged even there are no Thread sleep inside the loop. – Lalith J. Dec 05 '14 at 18:00
  • If you need to update some text shown in the GUI at a hight rate from other threads, I recommend using a StringProperty modified by your threads, that will be polled by a Timeline at say 60Hz to decouple the high change-rate from GUI Thread activities.... – Jens-Peter Haack Dec 05 '14 at 18:01
  • I do not understand, you mean bind a StringProperty to Label and update it ? I assume currently the code doing it. or you maned something else? if it is please give me an example . Thank you for your quick reply. – Lalith J. Dec 05 '14 at 18:06
  • I did that for a ProgressBar, showing progress of a multithreaded processing at many million operations per second... see: http://stackoverflow.com/questions/26805966/java-8-parallel-foreach-progress-indication/26814087#26814087 – Jens-Peter Haack Dec 05 '14 at 18:06
  • And finally: if the code currently works fine... no reason to change and waste time on my proposal :-D ;-) – Jens-Peter Haack Dec 05 '14 at 18:08
  • :-D Thank you for the suggestion. You are direct accessing the platform.rulater(); I am seeking an indirect approach, anyway Thank you again for the quick response. :) – Lalith J. Dec 05 '14 at 18:23
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/66284/discussion-between-lalith-jayasinghe-and-jens-peter-haack). – Lalith J. Dec 05 '14 at 18:59
  • It's also worth looking at how `Task.updateMessage()` is implemented: [source code](http://hg.openjdk.java.net/openjfx/8/master/rt/file/f89b7dc932af/modules/graphics/src/main/java/javafx/concurrent/Task.java) – James_D Dec 05 '14 at 19:24