Most of the newcomers eventually find out that Swing is not thread-safe, but this is most certainly not Swing’s “fault”. Other UI toolkits, such as SWT, Win32 API, Motif, Xlib and GTK are not thread-safe as well (Chet Haase and Graham Hamilton have written on this topic a few years ago). It’s just that Swing is very lenient on the application code that violates the Event Dispatch Thread rules that state that every interaction with UI component must be done from the single UI thread (EDT). Unlike SWT that is much more rigorous in this aspect (checking access and throwing runtime exceptions), most Swing violations may go unnoticed for a long time, creeping to the production environment and making it very hard to debug / reproduce the scenarios on our development machines.

The automatic tracing of EDT violations has been a subject of extensive entries on Alex Potochkin’s blog about two years ago (part 1, part 2 and part 3) and his eventual conclusion was that it is highly unlikely that the EDT rules will be enforced by the core Swing runtime code.

As i already mentioned,  these rules are very easy to break and quite tricky to track. I see a lot of “unorthodox” usage of Swing APIs from the users of Substance look-and-feel, and while most of it is correct, there are quite a few violations (quick search in the issue tracker came up with issues 156, 162, 163, 227, 283, 293 and 300). While most of these are manifested only under Substance due to a number of “behind-the-scenes” worker threads, nothing guarantees that these scenarios will not come up under other look-and-feels in the long term.

After thinking about this for a while i have decided to introduce a stricter EDT-related policy in the latest drops of the 5.0dev branch. A low-overhead check is done every time your application creates a Swing component that will have a UI delegate from Substance (in the “magic” static createUI method of all the UI delegates). In case an EDT violation is detected Substance will throw an IllegalStateException.

There are two issues to address here. The overall runtime performance should not be visibly affected. The check is only done when the component is created and not on every state change / paint / user interaction. While this does not go the whole way of more comprehensive techniques surveyed by Alex, it should detect quite a few rogue accesses. The second issue is that of potentially breaking the existing applications. This is an important issue for me as a library provider, but i do believe that it will result in better and more robust behavior of your applications in the long run.

The quicker you find a bug in your code, the easier it will be to fix. While this is not a compile-time check, the IllegalStateException will be thrown the very first time a component is created off EDT. Instead of postponing a possible application freeze / artifacts / data mangling / unpredictable behavior to your production environment, you will see the problem immediately on your development box. While this might be an annoyance in the short term, it should pay off greatly in the long term.

Going forward i do have plans to identify additional low-overhead candidates for checking EDT violations automatically inside Substance. This might involve accessing the models, views, listeners and other parts of the UI components.

The new policy is available in the latest drop of the core Substance library, as well as in the plugins for SwingX, Flamingo and JIDE components. As always, your feedback is highly appreciated.

Update: added a link to Graham Hamilton’s article (thanks to Javaposse for being better than Google)

Here are some Swing links that you might have missed during this week:

  • James Williams has a tongue-in-cheek list of five tips to tame Matisse layouts. This resonates with my earlier post on JBuilder and getting locked to an IDE that enforces any non-standard logic on the UI code that it creates.
  • Luan O’Carroll writes about distributing a WebStart application via CD-ROM, expanding on such subjects as WebStart cache, not relying on existing JRE installations, working with no Internet connection and others.
  • Build 27 of 6u10 is out and it addresses the issue that prevented applications from using the Synthetica look-and-feel. It also features performance improvements for Nimbus (about 8% as measured in the dynamic performance suite from the LightBeam project). Although not official, we can expect the release candidate of 6u10 this week.
  • Ken Orr writes about a custom implementation of placard button commonly found in Mac applications.
  • Alexander Potochkin introduces yet another useful feature of his JXLayer project – ability to lock (disable) the entire Swing container, including blocking any user interaction with its children.
  • The “Ask the Experts” session on 6u10 is over, and (much like two years ago), i had a question that was not addressed. I will be polite and blame the intratubes, but the topic at hand will be a subject of a forthcoming entry.

Every once in a while i get questions on using the Mac OS X menu bar for Swing applications running under Substance look-and-feel. This refers to the apple.laf.useScreenMenuBar VM flag that is respected by the native Aqua look-and-feel (and its third-party Quaqua extension). Up until this week the only advice that i could give was to use AWT menus (thanks to Quaqua’s author Werner Randelshofer for this). However, it is not the optimal solution for cross-platform Swing applications that wish to use Swing menus on non-Mac platform.

As i was thinking about this problem after being recently contacted by Sergiy Michka, i thought about an alternative solution which was later reviewed by Swing lead for Apple VM Mike Swingler. The solution is not specific to Substance and should work under other core and third-party look-and-feels that allow mixing menu UI delegates from other look-and-feels. Here is what you can do in your Swing application to have your menus appear on the global menu bar (in addition to setting the above VM flag):

  1. Check that you’re running under Apple VM. Use <font color="darkblue">System.getProperty("os.name")</font> and check that the value starts with “Mac”.
  2. Set Aqua (or the future default Apple VM platform look-and-feel) with <font color="darkblue">UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName())</font>.
  3. Query and store the following <font color="darkblue">UIManager</font> entries: “MenuBarUI”, “MenuUI”, “MenuItemUI”, “CheckBoxMenuItemUI”, “RadioButtonMenuItemUI”, “PopupMenuUI”.
  4. Set your look-and-feel of preference with <font color="darkblue">UIManager.setLookAndFeel</font> call.
  5. Before creating your first window, restore the <font color="darkblue">UIManager</font> entries for the keys specified in the third step.

Now the menus on the fronted frame will go into the global menu bar. It is not recommended to rely on the current class names for the Aqua UI delegates, since the package that hosts these classes is different for different versions of Apple VM. This is mentioned in the release notes for Apple VM 1.6.0 on Mac OS X 10.5 Leopard (radar #4907470).

Sleepless Nights - The Geek Bachelorette

 < Prev   Next >