Will the real Swing Single Threading Rule please stand up?

disclaimer: This entry isn’t intended for a general audience. If you’re not a Swing programmer, you’ll probably want to skip it.

This is what a Swing “hello world” program used to look like.

import javax.swing.*;

public class HelloWorld2002 {

	public static void main(String[] argv) {
		JLabel bulletin = new JLabel("Hello, world!", JLabel.CENTER);

		JFrame frame = new JFrame("Bulletin");
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.getContentPane().add(bulletin); // adds to CENTER
		frame.setSize(200, 150);
		frame.setVisible(true);
	}
}

This is pretty much the same as the code on page 85 of my book. In fact, just about all the examples in the book kick things off this way. They create JFrames and other JComponents in the main thread, either directly in main() or indirectly. Swing is not thread-safe (by design) so we have always had to be careful. For example, if we want to call bulletin.setForeground(Color.RED) after the frame is visible, we have to make sure it executes in the event-dispatching thread. If it executes in the main thread or some other thread it’s likely to work just fine, but there are no guarantees and it is possible that bad things (such as deadlock) may happen. Even if it seems to work on your development machine, it may fail intermittently, or it may even deterministically fail on some platform on which you haven’t tested or on some future release of the JDK.

Swing Single Threading Rule (through 2003)
Once a Swing component has been realized*, only the event-dispatching thread should affect or query the component.
*Realized means that the component has been painted onscreen, or is ready to be painted. The methods setVisible(true) and pack cause a window to be realized, which in turn causes the components it contains to be realized.

Several years ago I heard rumors that intermittent errors on the Solaris operating system could be worked-around by doing everything on the event-dispatching thread. By everything I mean not only the manipulation of realized components, but also of unrealized ones, and even the instantiation of the components themselves.

I never heard anything official in this regard, but it often pays to be cautious so I started doing this in most of my production code. I noticed that other Swing programmers started doing it in their code too.

Flash forward to last week. I was at a job interview. I had submitted a code sample that set up the GUI in the main thread, and now I was being asked about it. As a Swing expert, how could I have made such a common error?

I wasn’t worried about the code itself. I probably should have looked it over before submitting it as an interview code sample, but it had already served the purpose for which I had originally written it. But it did make for an awkward interview question. Obviously I had missed a decree from on high.

Or had I? If a decree had come down, I figured, a web search would find it easily. But no. I could find a few crumbs, but only a few, and nothing close to “official.” Hmm, that’s weird.

Eventually I was able to track down an archive of a page that no longer exists on java.sun.com. That link will let you view multiple versions of the page. Notice that the Oct 03, 2003 version gives the rule as quoted above, but starting with Apr 13, 2004 the rule changes.

Swing Single Threading Rule (2004 through 2006?)
To avoid the possibility of deadlock, you must take extreme care that Swing components and models are created, modified, and queried only from the event-dispatching thread. (emphasis added)

This is from the Java Tutorial, which would have to be considered “official.” Or at least it would be if the page (or one like it) still existed. It is interesting that they provide a note explaining why they made the change. It sounds like their ComponentEventDemo would occasionally deadlock (on Solaris only?) and rather than considering this a bug in the demo or in the (Solaris) JDK, they changed the Swing threading rule.

And thus every example program in my book and, for that matter, pretty much every Swing application and applet that had ever been written up to that point needed to be changed to be in compliance.

I’m not saying they changed the rule flippantly. I’ve met some of the Swing guys at Sun and they seemed conscientious. I’m sure that ComponentEventDemo itself didn’t have any threading bugs, and I’m willing to believe that there was no obvious way to update one or more JDKs to fix the problem. But I do wonder. Where is the sample code that exhibits why the change was needed? Where is the decree? Why is it so hard to find solid information on this topic?

It turns out the current Java Tutorial does agree with the new rule. It just doesn’t make as big a deal about it.

From the current Java Tutorial
Why doesn’t the initial thread simply create the GUI itself? Because almost all code that creates or interacts with Swing components must run on the event dispatch thread. This restriction is discussed further in the next section.
(Alas, the next section doesn’t actually discuss it much.)

By almost they mean that a few Swing methods are documented to be thread-safe. This has been true since the beginning of Swing.

Anyway, it seems that the Swing “hello world” app has become less intuitive for the beginner.

import javax.swing.*;

public class HelloWorld2005 {

	public static void main(String[] argv) {
		SwingUtilities.invokeLater(new Runnable() {
			public void run() {
				aggregate();
			}
		});
	}

	private static void aggregate() {
 		JLabel bulletin = new JLabel("Hello, world!", JLabel.CENTER);

		JFrame frame = new JFrame("Bulletin");
 		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
 		frame.getContentPane().add(bulletin); // adds to CENTER
 		frame.setSize(200, 150);
 		frame.setVisible(true);
	}
}

13 thoughts on “Will the real Swing Single Threading Rule please stand up?

  1. Alan Cole March 21, 2007 / 11:54am

    So if the Grand Pro of Java has done a surreptitious & retroactive Rule Change without telling anybody, & then tried covering its tracks, what else is out there to trip up the professionals in the field?

    Transparency in all this might heap embarrassment upon the Java Grand Pro, but it might also save untold trouble for lots of other folks.

    Sheesh.

  2. bassclar March 21, 2007 / 12:23pm

    I wouldn’t say that they were trying to cover their tracks, or even that the change was surreptitious. I don’t think this is an embarrassment issue. Noone denies that Java has had plenty of bugs and design flaws, and I would tend to call this just another one of those.

    The reason I created this entry was not to complain, but to throw some light on the issue and maybe elicit an official response from the powers that be.

    Or perhaps I have been living under a rock, the issue has already been lit adequately, and there has been an official response of sorts that I simply failed to find. If that’s the case, I’m hoping that knowledgeable readers post helpful URLs so I can come out from under my rock.

  3. flynnk March 23, 2007 / 2:11am

    I suppose since I asked the infamous interview question in the first place, I ought to chime in.

    If I was making up a list of reasonable or maybe even good interview questions, I’d probably put this on there. Mainly because I want to make sure that potential candidates keep up on language changes and whatever “the coming thing” is. BUT….

    There was a decree, but for the life of me I cannot remember where I heard it for the first time. I remember there was a bit of a buzz when it happened, but I’ve dug through a few google searches, notes from JavaOnes gone by, and links from the Tutorial. The best I can find is this tech tip from Sun:

    JDC Tech Tips

    It at least alerts you that they have changed something. I do seem to remember hearing about this first at JavaOne, but it was a long time ago. I may have also just noticed the change when I downloaded the updated tutorial–something I still do every so often, even if I rarely refer to it anymore, just so I know where to point other developers. I do recall going through all of my old code and dutifully changing to the new style when I did a newer release. To be honest, I doubt this ever actually caused a bug (at least one I knew about).

    The problem is that there really is a staggering lack of documentation on this. Even the tutorial itself has not been completely updated. Take a look at the Frames page:

    Frame Tutorial

    There’s still some mighty suspicious language in there, such as the word “realized.”

    I suppose that JSR 296 (Swing Application Framework) is going to magically fix this. I’m not holding my breath though. If someone could fix the JSR website which is COMPLETELY TOAST at the moment, I would link the JSR.

  4. flynnk March 23, 2007 / 2:19am

    Write a long post, and then you realize you missed something. The new policy does appear in one other place: the javax.swing package documentation in the main javadoc:

    javax.swing [I believe he intended to link here. -ed.]

    Of course, it mainly just points you at the tutorial.

  5. […] The Swing Application Framework has a number of goals, but one of them is to provide an Application class that has lifecycle methods for the programmer to implement, sort of like the existing Applet class. Application makes it easier not to violate the more-stringent Swing threading rule […]

  6. Alex June 12, 2007 / 10:21pm

    Where to begin! I’ve stumbled onto this entry through a series of blog-links that started at community.java.org, and whilst I am very glad to have found it, it’s a bit disconcerting when faced with the prospect that your entire application, coded the ‘old school’ way, may need a major overhaul.

    I have a faint understanding of the mechanics here, but to which granularity is this applicable? Is it only the creation of a Swing container that must be run in an invokeLater block? Is it instead any operation that adjusts anything to do with any Swing component?

    What a nightmarish task to wrap every setText( “abc”) in an invokeLater block… This is what we’re looking at?

    How does JSR 296 solve this? Any recipes to applying the SAF to existing applications that you would recommend?

    Thanks for the enlightenment!

    Regards.
    Alex

  7. Mike June 14, 2007 / 11:51am

    SetText(String) and the like are thread-safe (this is documented in their javadoc). Anything that is _not_ documented as thread-safe is considered to be thread-unsafe and should be wrapped in a Runnable and posted to the EDT. This especially applies to component models (table model, list model, maybe others). Though not technically part of Swing or the GUI (esp. if you code your custom model), changing the model must according to docs fire a change event, which in turn causes the GUI to update to reflect the change (JTables, JLists, etc. add themselves as change listeners to the model). The GUI updating must take place on the EDT, thus changing the model must also take place there. I don’t know if it’s acceptable for a very heavyweight model class (i.e. one communicating with a database) to do its stuff on some other thread and post only the fireXXXEvent() call on the EDT…

    • Blen January 27, 2011 / 3:04am

      Sorry for the late comment but I think it is important to clarify this “setText() issue”. In general such methods do not have to be wrapped in invokeLater blocks, no such nightmare needed.

      The reason for that is not that setText would be thread-safe, it is not. It has to be run in the event dispatch thread.

      [Note that setText() methods in Swing generally are documented to be thread-safe. This is why I talk about setForeground() instead. Checking the javadoc, however, I don’t see a designation that JLabel.setText() is thread-safe so you may be right. -ed]

      The real reason is that usually such code is executed in response to some event like when clicking a button or selecting a menu item, so the actual code in some event listener method which is already run by the EDT in the first place.

      [I don’t know if I would say “usually” here. If you know that your code (event handler or not) will only be called by the EDT then you are correct that there would be no need to wrap in something like SwingUtilities.invokeLater(). -ed]

Leave a comment