Swing, SWT, and most (maybe all?) GUI APIs operate under some sort of thread confinement scheme. Most readers of this blog are probably somewhat familiar with the AWT/Swing event dispatch thread. Swing components are not thread-safe — they are thread-confined. This means when you call methods on Swing components, you must ensure you do so on the event dispatch thread. There are a handful of thread-safe exceptions to the rule, such as repaint().
During our last meeting it was brought to my attention that SWT adheres to a fail-fast policy. If you invoke SWT API methods from a foreign thread, an SWTException is thrown. Yes! This is the way to do it.
Swing, on the other hand, does not fail fast. Instead, if you execute Swing API methods outside the EDT, your app might work…or it might exhibit strange behaviour. You might notice painting artifacts, obscure exceptions, and possibly may encounter memory visibility issues on multi-processor systems.
Can We Fix Swing?
I suspect that most developers will agree a fail-fast approach works best. If your code has a bug, you may as well fail immediately with a specific exception (as SWT does), rather than live with subtle bugs (as Swing does) that are much harder to diagnose.
One approach involves changing every method in Swing as follows:
public void doSomething() {
if (!SwingUtilities.isEventDispatchThread()) {
throw new IllegalStateException(“…blah blah blah…”);
}
…normal code
}
Of course those three lines of code could be encapsulated into a helper-function of some sort, but the concept remains the same. This would require sweeping changes to Swing and is unlikely to happen. Throwing an exception, while arguably correct, does change the contract of these methods. Even if we do not like the current behavior, changing the semantics of nearly every Swing method may break quite a bit of code.
A More Serious Proposal
I believe annotations offer a more viable solution. Imagine if Java 7 Swing code added annotations to every Swing method that requires the EDT:
@RequiresEDT
public void doSomething() {
…normal code
}
A new @RequiresEDT annotation would not change the behavior of any existing Swing API. It would, however, clearly document the intent of every Swing method. Furthermore, having that annotation in place (with runtime retention) makes it drop dead simple to use an AOP framework to enforce proper thread confinement. Or IDEs can more easily offer inspections that warn you of threading bugs.
Thoughts? Is this something we should pursue adding to Java 7?
Posted by Eric Burke