The Single Thread Rule in Swing
The Single Thread Rule in Swing
style="float: left; margin-right: 1em" />I am working on the 8th edition
of Core Java, and I just
received a batch of very thoughtful comments from
href="http://www.briangoetz.com/">Brian Goetz about the concurrency
chapter. (Thanks Brian!!!) He points out that I missed an important change
in the Swing single thread rule. (Judging by
href="http://bitguru.wordpress.com/2007/03/21/will-the-real-swing-single-threading-rule-please-stand-up/">this
blog, I am not the only author who did.)
The original rule is well explained in
href="http://java.sun.com/products/jfc/tsc/articles/threads/threads1.html">this
classic article. It is:
Once a Swing component has been realized, all code that might affect
or depend on the state of that component should be executed in the
event-dispatching thread.
“Realized” is defined in that article, and it is a bit
intricate. But for the most part, it means that you should stop messing
with Swing components in the main thread after calling pack (!)
or setVisible(true), whichever comes first.
For example, the following code would be
bad.
public class BadExample
{
public static void main(String... args)
{
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
frame.setSize(300, 300); // BAD
}
}
But the
href="http://java.sun.com/javase/6/docs/api/javax/swing/package-summary.html#threading">latest
Javadoc goes quite a bit further. It says “All Swing components
and related classes, unless otherwise documented, must be accessed on the
event dispatching thread.”
style="float: left; margin-right: 1em" />In other words, this example is
also bad:
public class StillBad
{
public static void main(String... args)
{
JFrame frame = new JFrame(); // BAD
frame.setSize(300, 300); // BAD
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // BAD
frame.setVisible(true); // BAD
}
}
The Javadoc then goes on: “The preferred way to transfer control
and begin working with Swing is to use invokeLater.”
style="float: left; margin-right: 1em" />Here is the example, rewritten
the good way.
public class PureGoodness
{
public static void main(String... args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
JFrame frame = new JFrame();
frame.setSize(300, 300);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
});
}
}
Ugh. That won't win the hearts and minds of my students. I suppose I
could rewrite it as
public class PureGoodness implements Runnable
{
public void run()
{
JFrame frame = new JFrame();
frame.setSize(300, 300);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
public static void main(String... args)
{
EventQueue.invokeLater(new PureGoodness());
}
}
Still ugh.
I am left with some questions and I fervently hope that some of you
have answers:
- What does it mean that this is the “preferred” way? What
other non-bad ways are there? Or is the bad approach not so bad after
all? - How can I come up with a tangible example of the badness of the bad
approach? href="http://bitguru.wordpress.com/2007/03/21/will-the-real-swing-single-threading-rule-please-stand-up/">Rumor
has it that href="http://java.sun.com/docs/books/tutorial/uiswing/examples/events/ComponentEventDemoProject/src/events/ComponentEventDemo.java">ComponentEventDemo
would deadlock on Solaris if the GUI was created in the main thread, but
that program has other threading problems, as evidenced by this
comment:
I tried creating a bad situation, but I was stymied by the factprotected void displayMessage(String message) {
//If the text area is not yet realized, and
//we tell it to draw text, it could cause
//a text/AWT tree deadlock. Our solution is
//to ensure that the text area is realized
//before attempting to draw text.
if (display.isShowing()) {
display.append(message + newline);
display.setCaretPosition(display.getDocument().getLength());
}
that on Linux (and, I believe, on Windows) the event dispatch thread is
never created until the call to setVisible. Core Java has a
convincing example that shows a combo box breaking when another thread
adds and removes items after the event dispatch thread has started. I
would very much like something similar that convinces readers to use
invokeLater when constructing the UI. - The Javadoc says that you should call
href="http://java.sun.com/javase/6/docs/api/javax/swing/SwingUtilities.html#invokeLater(java.lang.Runnable)">SwingUtilities.invokeLater.
According to that method's Javadoc, “As of 1.3 this method is just
a cover for java.awt.EventQueue.invokeLater().” So, why
not recommend to use EventQueue.invokeLater? It seems clearer,
and it is four letters shorter. - Should I really go through the trouble of
style="text-decoration: line-through;">uglifying correcting
dozens of Swing examples in Core Java? Is it worth worrying about it?
After all, there must be thousands of programs out there that rely on
the old version of the single thread rule.
- Login or register to post comments
- Printer-friendly version
- cayhorstmann's blog
- 4710 reads





