103

I have been doing some research on this but I am still VERY confused to say the least.

Can anyone give me a concrete example of when to use Task and when to use Platform.runLater(Runnable);? What exactly is the difference? Is there a golden rule to when to use any of these?

Also correct me if I'm wrong but aren't these two "Objects" a way of creating another thread inside the main thread in a GUI (used for updating the GUI)?

randers
  • 5,031
  • 5
  • 37
  • 64
Marc Rasmussen
  • 19,771
  • 79
  • 203
  • 364

4 Answers4

126

Use Platform.runLater(...) for quick and simple operations and Task for complex and big operations .

Example: Why Can't we use Platform.runLater(...) for long calculations (Taken from below reference).

Problem: Background thread which just counts from 0 to 1 million and update progress bar in UI.

Code using Platform.runLater(...):

final ProgressBar bar = new ProgressBar();
new Thread(new Runnable() {
    @Override public void run() {
    for (int i = 1; i <= 1000000; i++) {
        final int counter = i;
        Platform.runLater(new Runnable() {
            @Override public void run() {
                bar.setProgress(counter / 1000000.0);
            }
        });
    }
}).start();

This is a hideous hunk of code, a crime against nature (and programming in general). First, you’ll lose brain cells just looking at this double nesting of Runnables. Second, it is going to swamp the event queue with little Runnables — a million of them in fact. Clearly, we needed some API to make it easier to write background workers which then communicate back with the UI.

Code using Task :

Task task = new Task<Void>() {
    @Override public Void call() {
        static final int max = 1000000;
        for (int i = 1; i <= max; i++) {
            updateProgress(i, max);
        }
        return null;
    }
};

ProgressBar bar = new ProgressBar();
bar.progressProperty().bind(task.progressProperty());
new Thread(task).start();

it suffers from none of the flaws exhibited in the previous code

Reference : Worker Threading in JavaFX 2.0

Andrii Abramov
  • 10,019
  • 9
  • 74
  • 96
invariant
  • 8,758
  • 9
  • 47
  • 61
  • Task Example in Ensemble App link won't work anymore. – Cugomastik Aug 05 '14 at 14:21
  • [This is the correct link](http://download.oracle.com/otndocs/products/javafx/2/samples/Ensemble/index.html#SAMPLES/Concurrency/Task) but I can't edit it in because the edit is only 2 characters. – Aerus May 01 '15 at 11:28
  • 39
    To say that one for "quick" operations and another for "complex" ones is a bit misleading. The main difference, after all, is that one allows to run code in the JFX GUI thread from somewhere else, and the other one does the exact opposite - allows to run code in the background thread from the GUI thread (adding a bonus of being able to communicate with the GUI thread in the process). – Sergei Tachenov May 02 '15 at 17:22
  • I want to save an Image of each of the scenes - and this will take time. Will that cause issues when run on a separate thread via Task? I understood that all gui related work needs to happen on the FxApplication thread. – WestCoastProjects Aug 09 '15 at 15:31
  • @Sergey-Tachenov So you use runLater() from a Task thread to update the GUI thread in cases where you want to do more than just update a single property like progress? – simpleuser Mar 15 '16 at 16:41
  • @user1663987, yeah, you could do that in case you don't do it too often. Or (and I like it better) you could use the `updateValue()` method and make the `value` property encapsulate whatever you need to display in the GUI. – Sergei Tachenov Mar 15 '16 at 17:24
  • which Task should I use? `javafx.concurrent.Task` or `com.sun.jmx.snmp.tasks.Task` – Rahul Yadav Jun 28 '17 at 13:24
  • You don't need to declare Runnables like this any more. You can use lambda syntax: `() -> { // Code here }`, or () -> `runSingleThing();`. So, the above code would condense a lot and wouldn't look so overwrought. The answer is still perfectly valid though :) – ManoDestra Aug 09 '17 at 21:57
69
  • Platform.runLater: If you need to update a GUI component from a non-GUI thread, you can use that to put your update in a queue and it will be handled by the GUI thread as soon as possible.
  • Task implements the Worker interface which is used when you need to run a long task outside the GUI thread (to avoid freezing your application) but still need to interact with the GUI at some stage.

If you are familiar with Swing, the former is equivalent to SwingUtilities.invokeLater and the latter to the concept of SwingWorker.

The javadoc of Task gives many examples which should clarify how they can be used. You can also refer to the tutorial on concurrency.

gravetii
  • 9,273
  • 9
  • 56
  • 75
assylias
  • 321,522
  • 82
  • 660
  • 783
  • Thank you Can you give a small example of how to use platform ? Can you use it outside the gui thread or? And the task examples in the docs are really unclear – Marc Rasmussen Dec 09 '12 at 12:33
  • Yes Platform.runLater can be used outside the GUI thread - that's its main purpose. You might find this [tutorial](http://docs.oracle.com/javafx/2/threads/jfxpub-threads.htm) on tasks more informative than the javadoc. – assylias Dec 09 '12 at 12:40
  • 3
    You use Platform.runLater like this: `Platform.runLater(new Runnable() {public void run() {updateYourGuiHere();}});` – assylias Dec 09 '12 at 12:41
  • how will i be able to use the GUI components then = :S – Marc Rasmussen Dec 09 '12 at 13:51
  • @MarcRasmussen I'm not sure I understand your question. – assylias Dec 09 '12 at 15:47
  • say that a new chat person connects to my chat program. now i want to update the list of my online people how would i update that textarea from another class? – Marc Rasmussen Dec 09 '12 at 17:56
  • @MarcRasmussen It is difficult to answer with so little details. I suggest you ask a separate question where you show the code you have and explain what you are trying to achieve. – assylias Dec 09 '12 at 18:00
  • Re: `"but still need to interact with the GUI at some stage"`, does `at some stage` mean the `Task` can use the JavaFX Application Thread? – Kevin Meredith Dec 29 '16 at 15:15
  • 1
    @KevinMeredith The call method of the Task should not be called on the FX thread - but Task provides bridge methods (updateProgress etc.) that run on the FX thread. See the javadoc & tutorials for more info. – assylias Dec 29 '16 at 15:46
14

It can now be changed to lambda version

@Override
public void actionPerformed(ActionEvent e) {
    Platform.runLater(() -> {
        try {
            //an event with a button maybe
            System.out.println("button is clicked");
        } catch (IOException | COSVisitorException ex) {
            Exceptions.printStackTrace(ex);
        }
    });
}
randers
  • 5,031
  • 5
  • 37
  • 64
Cugomastik
  • 911
  • 13
  • 22
  • 8
    If you are handling a GUI event, you are in the GUI thread. Why would you use runLater() then? – TFuto May 12 '15 at 15:03
  • While you're right, Caglar's answer was trying to highlight the use of a lambda expression, not necessarily to give a good coding example. I use `Platform.runLater(() -> progressBar.setProgress(X/Y));` – Taelsin Nov 16 '16 at 16:40
3

One reason to use an explicite Platform.runLater() could be that you bound a property in the ui to a service (result) property. So if you update the bound service property, you have to do this via runLater():

In UI thread also known as the JavaFX Application thread:

...    
listView.itemsProperty().bind(myListService.resultProperty());
...

in Service implementation (background worker):

...
Platform.runLater(() -> result.add("Element " + finalI));
...