FX Experience Has Gone Read-Only

I've been maintaining FX Experience for a really long time now, and I love hearing from people who enjoy my weekly links roundup. One thing I've noticed recently is that maintaining two sites (FX Experience and JonathanGiles.net) takes more time than ideal, and splits the audience up. Therefore, FX Experience will become read-only for new blog posts, but weekly posts will continue to be published on JonathanGiles.net. If you follow @FXExperience on Twitter, I suggest you also follow @JonathanGiles. This is not the end - just a consolidation of my online presence to make my life a little easier!

tl;dr: Follow me on Twitter and check for the latest news on JonathanGiles.net.

For the past couple of years the industry has continued to follow Moore’s Law by shifting from CPU clock speed to increasing the number of cores and threads per core. Even cell phones are getting multiple cores these days! Taking advantage of all these cores and threads is one of the hallmarks of modern GUI platforms. But all this concurrency brings a multitude of problems to the application developer, not least of which is that writing multithreaded applications is hard!

In designing JavaFX 2.0, we of course needed to address both how the scene graph would behave in the presence of multiple threads, and how developers could effectively do work in background threads and keep the UI responsive. In short, the JavaFX scene graph, like all other mainstream GUI toolkits, is not thread-safe and must be accessed and manipulated from the UI thread (call the FX Application thread). Swing and AWT had the same basic policy (only work with Swing or AWT from the Event Dispatching Thread), as did SWT (only interact with SWT resources and components from the thread that owns them), as do all other major toolkits (JavaScript / HTML included).

The most common problem with this design is that developers who do not do work on background threads invariably create unresponsive applications, since this long lived (potentially blocking) code happens on the same thread that processes user events. That is, while your long lived operation is running, no mouse or key events are being processed, which leads to an application that appears to “hang”.

Further, actually writing well behaved background workers is difficult and error prone. Even if you create a Runnable and create a Thread and do your long-lived work in that background thread, at some point you need to communicate back to the UI, either with the result of the long-lived computation, or by communicating to a ProgressIndicator of some kind what the progress of this long-lived operation is. This is error prone, because you must be sure to communicate with the UI by putting events back onto the event queue (using Platform.runLater, the equivalent of Swing’s invokeLater).

Note: This article is a sneak peek at a new API which is coming in the next couple of weeks, but is not currently available in the Beta builds! There is a deprecated Task class in the beta builds which will be removed and replaced with the one detailed here.

Suppose we have a simple background thread which just counts from 0 to 1 million. Suppose I have a single ProgressBar, and that I need to update the progress of this ProgressBar as the counter runs. A naive implementation might look like this:

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.

Java comes with a very complete set of concurrency libraries in the java.util.concurrent package. We wanted to leverage what was already defined in Java, but we needed to extend these APIs to take into account the FX Application thread and the constraints that GUI programmers are under. The javafx.concurrent package contains three core files: Worker, Task, and Service.

Before diving into the rather verbose description (taken from the proposed javadocs) for Worker, Task, and Service I wanted to cut to the chase and show some examples. The first key thing to mention, is that Worker is an interface that is implemented by both Task and Service, and which adds the sort of convenience API necessary for a background worker that is useful for communicating back with a UI. Second, Task extends from java.util.concurrent.FutureTask. This means that a Task can very cleanly fit into the concurrent libraries. As you may know, FutureTask implements Runnable, and can be passed to an Executor’s execute() method.

So real quick, here is the same example as above, but it suffers from none of the flaws exhibited in the naive implementation.

Task task = new Task<Void>() {
    @Override public Void run() {
        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();

In this example, I first create my Task. The task implementation just does its work, invoking the protected updateProgress method defined on Task, which ends up updating progress, totalWork, and workDone properties on the Task. I then create my ProgressBar and bind its progress property with the progress property of the Task. Then, since Task is a Runnable, I can just create a new Thread passing it the Task and then start the Thread.

Alternatively, I could create an Executor or ExecutorService (such as a ThreadPoolExecutorService) and execute the task using the ExecutorService.

Edit July 11, 2011: I have updated the API slightly since this post was originally written, and I’ve updated the post to reflect the current names. In particular, the “progress” property is now a value between 0 and 1 (or -1), matching the “progress” property on ProgressIndicator and other parts of the platform. “workDone” and “totalWork” are used to indicate the total units of work to do (such as bytes to be downloaded) and the total units of work that have been done (such as the bytes that have been downloaded). I’m not totally jazzed by the names, but felt it was important for “progress” to mean the same thing on Worker and ProgressIndicator.

Below are some further descriptions taken from the javadocs.

Worker

A Worker is an object which performs some work in one or more background threads, and who’s state is observable and available to JavaFX applications and is usable from the main JavaFX Application thread. This interface is primarily implemented by both Task and Service, providing a common API among both classes which makes it easier for libraries and frameworks to write user interfaces with observable workers.

A Worker may, or may not be reusable, depending on the implementation. A Task, for example, is not reusable while a @link Service is.

A Worker has a well defined life cycle. Every Worker begins in the READY state. When the Worker has been scheduled for work (for example, when a Service’s start() method is called), it is transitioned to SCHEDULED. Even Workers which are not technically scheduled, but started immediately (such as with Task#run()) will transition through SCHEDULED on its way to the RUNNING state.

When the Worker is actually performing its work, the state will have been transitioned to RUNNING. If the Worker completes normally, it will end in the SUCCEEDED state, and the result of the Worker will be set as the value property. If however an Exception occurs during the execution of the Worker, then the state will be set to FAILED and the exception property will be set to the Exception which occurred.

At any time prior to the conclusion of the Worker (that is, if the state is not already SUCCEEDED or FAILED) the developer may invoke the Worker#cancel() method. If called, the Worker will cease execution (if possible, including use of Thread.interrupt) and the state changed to CANCELLED.

The only valid beginning state for a Worker is READY, and the valid ending states are CANCELLED, SUCCEEDED, and FAILED. The running property is set to true when the state is either SCHEDULED or RUNNING.

The Worker’s progress can be monitored via three different properties, workDone, totalWork, and progress. These properties are set by the actual implementation of the Worker interface, but can be observed by anybody. The workDone is a number between -1 (meaning indeterminate progress) and totalWork, inclusive. When workDone == totalWork the progress will be 100% (or 1). totalWork will be a number between -1 and Long.MAX_VALUE, inclusive. The progress will be either -1 (meaning indeterminate), or a value between 0 and 1, inclusive, representing 0% through 100%.

A Worker which is in the READY or SCHEDULED states will always have workDone and progress set to -1. A Worker which is in the SUCCEEDED state will always have workDone == totalWork and progress == 1 or -1. In any other state, the values for these properties may be any value in their respective valid ranges.

Task

A fully observable implementation of a FutureTask. Tasks exposes additional state and observable properties useful for programming asynchronous tasks in JavaFX, as defined in the Worker interface. An implementation of Task must override the Task#call() method. This method is invoked on the background thread. Any state which is used in this method must be safe to read and write from a background thread. For example, manipulating a live scene graph from this method is unsafe and will result in runtime exceptions.

Tasks are flexibly and extremely useful for the encapsulation of work. Because Service is designed to execute a Task, any Tasks defined by the application or library code can easily be used with a Service. Likewise, since Task extends from FutureTask, it is very easy and natural to use a Task with the java concurrency java.util.concurrent.Executor API. Finally, since a Task is Runnable, you can also call it directly (by invoking the Task#run() method) from another background thread. This allows for composition of work.

Although java.util.concurrent.ExecutorService defines several methods which take a Runnable, you should generally limit yourself to using the execute method inherited from java.util.concurrent.Executor.

As with FutureTask, a Task is a one-shot class and cannot be reused. See Service for a reusable Worker.

Because the Task is designed for use with JavaFX GUI applications, it ensures that every change to the public properites, as well as change notifications for state, errors, and for event handlers, all occur on the main JavaFX application thread. Accessing these properties from a background thread will result in runtime exceptions being raised.

Service

A Service is a non-visual component encapsulating the information required to perform some work on one or more background threads. As part of the JavaFX UI library, the Service knows about the JavaFX Application thread and is designed to alieviate the application developer from the burden of manging multithreaded code that interacts with the user interface. As such, all of the methods and state on the Service are intended to be invoked exclusively from the JavaFX Application thread.

Service implements {@link Worker}. As such, you can observe the state of the background operation and optionally cancel it. Service is a reusable Worker, meaning that it can be reset and restarted. Due to this, a Service can be constructed declarativley and restarted on demand.

If an java.util.concurrent.Executor is specified on the Service, then it will be used to actually execute the background worker. Otherwise, a daemon thread will be created and executed. If you wish to create non-daemon threads, then specify a custom Executor (for example, you could use a ThreadPoolExecutor).

Because a Service is intended to simplify declarative use cases, subclasses should expose as properties the input parameters to the work to be done. For example, suppose I wanted to write a Service which read the first line from any URL and returned it as a String. Such a Service might be defined, such that it had a single property, url. It might be implemented as:

public class FirstLineService extends Service {
    private StringProperty url = new StringProperty();
    public final void setUrl(String value) { url.set(value); }
    public final String getUrl() { return url.get(); }
    public final StringProperty urlProperty() { return url; }

    protected Task createTask() {
        final String _url = getUrl();
        return new Task<InputStream>() {
            protected String call() {
                URL u = new URL(_url);
                BufferedReader in = new BufferedReader(
                        new InputStreamReader(u.openStream()));
                String result = in.readLine();
                in.close();
                return result;
            }
        }
    }
 }

Conclusion

We anticipate that libraries of Tasks, both specialized for your specific application and also general libraries of Tasks will be developed over time that perform common operations such as downloading files, performing HTTP form submits, copying files, uploading files, sorting, doing statistical analysis, and so forth. These reusable bodies of code can then be combined together, used with thread pools or other rich executor services, and used with Services.

Let us know what you think!