Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

JavaFx: the hidden threading rule

DZone's Guide to

JavaFx: the hidden threading rule

· Java Zone
Free Resource

The single app analytics solutions to take your web and mobile apps to the next level.  Try today!  Brought to you in partnership with CA Technologies

The following post is the result of my latest JavaFx Script experiments mixed with Stu's Java.Next series ( 1, 2). Alright, so Stu decides to showcase how the Java.next languages interop with Java the language, and to do so he chose a Swing based example. Though he did a great job covering each transformation from the original Java example to each of the Java.next candidates, the original example has a slight flaw: it doesn't honor Sun's guidelines for building Swing apps, mainly when creating components and/or changing a component's UI state you must do it inside the Event Dispatch Thread.

You can't really blame Stu for it, he is surely more of server/web developer than a desktop one so he probably wasn't aware of the guidelines, he took the code from a JRuby example, which most likely was taken from somewhere else. The real problem is twofold
  • bad programming examples since the early days of Swing.
  • no way to enforce Sun's Swing guidelines at the compiler level (some tools may provide stricter checks)

Because the amount of bad examples (by bad I mean those that do not follow the guidelines) is much more than the good ones we keep falling in the same hole over and over. The second reason can be mitigated by external tools as code checkers and IDEs. The following example does follow Sun's guidelines, which goes to prove the high level of ceremony of Java the language

import javax.swing.JFrame;
import javax.swing.JButton;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;

public class Swing {
public static void main(String[] args) {
SwingUtilities.invokeLater( new Runnable() {
public void run() {
JFrame frame = new JFrame("Hello Swing");
JButton button = new JButton("Click Me");

button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
JOptionPane.showMessageDialog(null,
String.format("<html>Hello from <b>Java</b><br/>" +
"Button %s pressed", event.getActionCommand()));
}
});

frame.getContentPane().add(button);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
} );
}
}

In Java Swing you must always have to take extreme precautions about threading, one bad move and your app will appear to be unresponsive when doing a long-term computation, scaring the user away. Regular Swing applications will run from the main thread, thus leaving you the task to properly wrap your code with SwingUtilities. What does this have to do with JavaFx Script? there it happens the complete opposite. Every single JavaFx application runs inside the Event Dispatch Thread, always, period. This means you no longer have to worry about paint/repaint issues when changing UI state _but_ you still need to take care of long computations as they will be run inside the EDT. The following fx script demonstrates this fact

import java.lang.System;
import javax.swing.SwingUtilities;
import java.lang.Thread;

class MyThread extends Thread {
override function run():Void {
System.out.println("inside MyThread");
System.out.println( SwingUtilities.isEventDispatchThread() );
}
}

System.out.println( SwingUtilities.isEventDispatchThread() );
var t = new MyThread();
t.start();
// --- output
// true
// inside MyThread
// false

 Once you jump out of the EDT you will eventually need to go back to update UI state. There is no current shortcut alternative for JavaFx (the jfx team is still working on it), so perhaps we shouldn't put away SwingWorker just yet. In case you are wondering you can't extend SwingWorker from JavaFx Script (at least not in a way I could find) given that it doesn't support generics declarations (yet). The alternative right now is pretty simple, drop down to the Java level, subclass SwingWorker and use it from your JavaFx scripts.

Now I'd like to show the Groovy alternative with a modified example, instead of displaying a dialog when the button is clicked, its text will change color from black to red and back

import groovy.swing.SwingBuilder
import javax.swing.SwingUtilities
import static javax.swing.JFrame.EXIT_ON_CLOSE
import java.awt.Color

int count = 0
SwingBuilder.build {
println "building ui inside EDT? ${SwingUtilities.isEventDispatchThread()}"
frame( title: "Hello Swing", pack: true, show: true,
defaultCloseOperation: EXIT_ON_CLOSE ) {
button( "Click Me", actionPerformed: { evt ->
println "action handler inside EDT? ${SwingUtilities.isEventDispatchThread()}"
doOutside {
println "long computation inside EDT? ${SwingUtilities.isEventDispatchThread()}"
doLater {
println "UI state change inside EDT? ${SwingUtilities.isEventDispatchThread()}"
evt.source.foreground = count++ % 2 ? Color.BLACK : Color.RED
}
}
})
}
}

Once you run the example you'll get the following output

building ui inside EDT? true

Which means that SwingBuilder took care of properly building the UI inside the EDT, the static build() method runs on the EDT. Clicking on the button once yields the following output

action handler inside EDT? true
long computation inside EDT? false
UI state change inside EDT? true

Two methods should catch your attention: doOutside and doLater. Those are handy threading abstractions provided by SwingBuilder. The first one spawns a new thread and runs the closure on it, the second one makes sure the closure is run inside the EDT. Simple, easy, Groovy. But if these threading facilities are not enough you can always subclass SwingWorker (in Groovy as it supports generics and other Java5 features) and plug it in.

The road to JavaFx Script 1.0 is still ahead of us, the JavaFx platform continues to be under construction, expect some updates on threading, hopefully by the time 1.0 is released.

</rant>

Note: I do not posses any inside information on JavaFx, all this material is the result of my own explorations and blog posts around the web.

 

CA App Experience Analytics, a whole new level of visibility. Learn more. Brought to you in partnership with CA Technologies.

Topics:

Published at DZone with permission of Andres Almiray. See the original article here.

Opinions expressed by DZone contributors are their own.

THE DZONE NEWSLETTER

Dev Resources & Solutions Straight to Your Inbox

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.

X

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}