/ Desktop Application Framework (JSR 377) / Concurrency in UI Toolkits (Part 1)

Concurrency in UI Toolkits (Part 1)

Hendrik on 2015/01/19 - 18:49 in Desktop Application Framework (JSR 377), JavaFX

Today every UI toolkit that is not running in a browser needs an UI Thread the handle the repainting and the event handling of the UI. Examples for this kinds of UI Toolkits are iOS, Android, SWT, JavaFX or Swing. Each of this toolkits defines a thread that will handle all the ui specific calls. Let’s call this thread “UI Thread”.
ui-thread

By definition all calls that will affect the UI or get data of the UI must be called on this thread. Accessing the UI from another thread than the UI Thread will result in a lot of different problems.

Normally all user events that are handled by the toolkit will be called on the UI thread. Therefore an event handler will be called on the thread, too. If a developer wants to interact with UI components as a result of an user event he can do this directly in the handler. The following code shows some pseudo code how this might look. Normally each UI Toolkits provide it’s own mechanism for event handling.

If you want to interact with the UI from outside of an event you need to invoke your code on the “UI Thread”.
invokeLater

Each UI Toolkit provides a helper method to handle this invocation. In a UI Toolkit independent and unified way this method might look like this:

By doing so any runnable can be called on the UI Thread. This is ok for some general use cases but it’s definitely not enough to create an big application. One of the big problems is that you don’t know when the code will be called and when the call is finished. The definition of this method only says that the code will be called in some future on the UI Thread. Therefore we need a second method that blocks until the call is finished.
invokeAndWait

In most cases this method will have the same signature as the previous one. Let’s define the method in a unified way:

Thanks to Java 8 we can define this method as a default method based on the other one:

This looks good so far but there is still a problem. As said the UI must only be accessed by using the UI Thread. Let’s think about a background thread that want’s to call a web service based on some user input. To do so the thread needs to know the input of a textfield, for example. Because we can’t access the text from the background thread we need to invoke the call to the UI Thread:
access

The following code shows how such a call might look like:

To do so we need another helper method:

In addition we can provide a method that won’t block until the call is finished:

Now we have a set of methods that can be used to interact with the UI Thread:

Let’s have a deeper look how we can implement this methods by using default methods:

As you can see there are 2 differences to the basic interface definition. First we need to throw some exceptions because calling the get() method of a Future instance will throw exceptions. These exceptions are needed. Let’s think your runnable call that accesses the UI will contain an error and throws an exception. In this case you want to know about the error when checking the result of the call. As a next change the Provider result type of one method is changed to Future. Internally a Future is used that can’t be casted to the Provider interface. In addition a Provider won’t define the needed Exceptions as described earlier.

Conclusion

The defined interface contains only one method that needs to be implemented in a UI Toolkit specific way to create some helper methods. This is a good start but some of you might know, that there are still some problems in this methods. Maybe you call a *AndWait(..) method from the UI Thread. This will maybe end in a deadlock. In addition the Future interface defines the method “boolean cancel(boolean mayInterruptIfRunning)”. What happens if we call this on a task that is executed by the UI Thread? This issues will be discussed in the next post.

8 POST COMMENT

Send Us A Message Here

Your email address will not be published. Required fields are marked *

8 Comments
  • Pingback:JavaFX links of the week, February 2 // JavaFX News, Demos and Insight // FX Experience

  • 2015/02/02

    Sometimes people wonder why multi-threaded GUI toolkits are not the norm, and why toolkits are structured around a single threaded architecture, especially in a modern environment of multi-core processors. I think it is useful to read Multi-threaded toolkits: A failed dream? to help understand why there is just one “UI Thread” even in today’s UI toolkits.

    jewelsea
    Reply
  • 2015/02/15

    jewelsea, what is an example of “today’s UI toolkits”? All of the major ones used today are quite old.

    Cocoa is from the 1980s. Qt is from 1991. MFC is from 1992, building upon older technology. AWT is from 1995. Swing is from 1996. GTK+ is from 1997. SWT and wxWidgets just build upon these old toolkits. Windows Forms is maybe the newest, from the early 2000s.

    There hasn’t been a widely used UI toolkit created in the past decade, if not longer. The best we’ve seen since then are half-assed UIs built using HTML/CSS/JS, and limited mobile UIs (think Android).

    JIMMYBOY
    Reply
    • 2015/02/15

      What’s with JavaFX?

      Reply
    • 2015/02/15

      Well WPF (2006) and was supposed to be the successor of WinForms.
      It had some good approaches, but the half-assed support from MS’ side prevented its breakthrough i guess.

      Phil
      Reply
  • 2015/02/15

    Some other comments about this post can be found at Hacker News: https://news.ycombinator.com/item?id=9050452

    Reply
  • 2015/02/15

    I’m confused about why you’re calling back to the GUI thread to get the text. Why not grab the text value in your click handler and pass that to your runnable/worker thread? Either as a constructor parameter or as a non-parameter variable referenced by a lambda?

    ngm
    Reply
    • 2015/02/15

      Hi,
      this will work if the method is called by an action handler on the ui thread. But maybe this method is called from a background thread all 500 ms. In this case you need to do it this way.

      Reply