Unwritten rule of working with Swing’s EDT

December 6th, 2007

The threading rules in Swing are one of the main reasons for the perceived slowness of Java desktop applications (it remains to be seen whether JavaFX will address this issue for anything other than toy demo applications that have started appearing lately). This article by John Zukowski is an excellent overview of the threading rules in Swing since its inception, and how to write applications that do not break the thread safety.

All different EDT-related rules pretty much boil down to one simple thing – anything that affects pixels on the screen should be done on EDT. However, these rules are all concerned about the where and not the when. And the when is very important. Here is the rule all Swing applications should abide by:

Event listener logic that affects pixels on the screen should schedule its execution after the current event has been processed by all registered event listeners.

The reason for doing this is simple – your application listener is not the only one that is registered for that specific event type. You might think that it’s the only one – after all, you know your application code inside out. However, there is much more going on “under the hood”, and that depends on the look-and-feel you’re using.

The look-and-feel doesn’t have any magic way of tracking the application state. Since the UI delegates use the same event / listener mechanism to track changes to control models, they rightfully expect the application logic to not interfere with the component state while the current change is being processed.

A simple example – application logic registers an action listener on a button. The action listener logic changes the UI state of the application (transitions to the next screen of the wizard, for example) and hides this button. After this action listener is done, the next action listener is called. What does it see? Surprise surprise – the button is no longer in the same state as it was when it was actually pressed.

The solution is very simple – wrap your action listener logic in SwingUtilities.invokeLater. I know, it makes the code ugly. I know, it makes the code go so much to the right side of your editor that you start hating Swing and contemplate switching to VB. But it is simply the right thing to do. You wouldn’t want any other listener to do that to the event source component, so why are you doing it yourself?