This is an update to the following blog posts:

Easily Find Swing Threading Issues - Part I

Easily Find Swing Threading Issues - Part II

I got an official comment on this issue from Scott Violet, JFC/Swing Lead at Sun:

    Swing's rules on threading have been problematic from the start. While creating components on another thread it is trivial to start generating events that are delivered to the component on the event dispatch thread resulting in two threads hitting the same component. Something Swing was not designed to deal with. As we've started to see more and more problems happen as a result of this we decided to revise our rules to be more realistic.

    It's true that often times you can get away with creating components on another thread and never see any problems, but it's much easier for us to say create everything on the event dispatching thread and don't worry about it. Ideally we would have an Application class that provides a place for you to create your GUI and isolated you from the main thread/event dispatching thread differences.

There is also more recent information from Sun than the article I previously linked to:

How to Use Threads

MultiThreading in Swing

So where does that all leave us? Well it looks as if the new guideline is to not create things off the EDT. If you do create things definitely don't realize them or modify them off the EDT.

Now on to a couple comments on the ThreadCheckingRepaintManager. I have uploaded a new version. With this version I have added the ability to specifiy an isShowing() check. So if you follow the "everything on the EDT thread rule", don't allow nonrealized components to be accessed outside the EDT thread by turning the check off. If you do thread things, you can turn it on to minimize output. I've also added the dump of the component tree with visibility settings when a "violation" is found. Sometimes this is useful when you are adding components to containers that you thought were not visible yet.

Finally, lets talk about the thread safe methods of repaint(), revalidate(), and invalidate(). I've added an example in the ThreadCheckingRepaintManager source of calling those methods off the EDT. The revalidate() method is wrapped in SwingUtilities.invokeLater() if called off the EDT so it is ok. The invalidate() method seems to call some layout manager voodoo. If you look at repaint() in Component it delegates down to a repaint(long tm, int x, int y, int width, int height). This method queues Paint events on the Event Queue eventually through a synchronized method. JComponent overrides this repaint method and adds dirty regions to the RepaintManager. This call is synchronized as well.

The repaint() method causes problems for the ThreadCheckingRepaintManager that I'm trying to figure out. Calling repaint directly from a non EDT thread is ok. However, I'm pretty sure as one blog comment pointed out there is code in Swing components that call repaint that isn't thread safe. So you end of with a stack of methods getting to the ThreadCheckingRepaint manager that goes through a thread safe method but isn't really thread safe. I've thought about parsing the stacktrace but that won't solve the problem above. For the moment I'm just going to leave repaint calls in as being flagged.

If anyone has anymore suggestions please let me know. The comments thus far have been very useful. I don't claim that this tool finds every problem or handles every case like the repaint() method. I'm hopeful thought is it a useful tool in identifying a good amount of Swing related threading issues that people have in their code.

ThreadCheckingRepaintManager Source and Examples


Really enjoy this article. I did a 'Launcher' for a client and it made several GUI applications share the same JVM. You can find details about how to build one in the Java Platform Performance book by Wilson & Kesselman. Have you considered keeping the main thread around for later use and passing it something via a ServerSocket using 127.0.0.1? As long as you use the Main thread shouldn't you be OK? Just a thought. Not sure how you would resolve adding components though unless you used a collection container like a static Map and pulled it out when needed by a JCompnent container. This is how the plugin models usually do it but I've never looked at the problem from this angle.
Spin (http://spin.sf.net) will include a checking RepaintManager in its next release - thank you very much for this nice idea.
Would it be possible to keep our efforts coordinated? I would be happy to integrate patches if you have enhancements. I'm also fine releasing a new version with a unrestrictive license that allows you to redistribute the source as you wish. I would like to keep this site as the location for source if possible. Numerous links have been made to the three blog posts I have done on the subject. Finally, I'd be glad to post another followup mentioning its inclusion in Spin and any enhancements you contribute.
----------Wrong Thread START
java.lang.Exception
	at dk.ifad.gui.ThreadCheckingRepaintManager.checkThread(ThreadCheckingRepaintManager.java:29)
	at dk.ifad.gui.ThreadCheckingRepaintManager.addDirtyRegion(ThreadCheckingRepaintManager.java:52)
	at javax.swing.JComponent.repaint(JComponent.java:4485)
	at java.awt.Component.imageUpdate(Component.java:2939)
	at javax.swing.JLabel.imageUpdate(JLabel.java:874)
	at sun.awt.image.ImageWatched$WeakLink.newInfo(ImageWatched.java:114)
	at sun.awt.image.ImageWatched.newInfo(ImageWatched.java:151)
	at sun.awt.image.ImageRepresentation.setPixels(ImageRepresentation.java:454)
	at sun.awt.image.ImageDecoder.setPixels(ImageDecoder.java:108)
	at sun.awt.image.GifImageDecoder.sendPixels(GifImageDecoder.java:428)
	at sun.awt.image.GifImageDecoder.parseImage(Native Method)
	at sun.awt.image.GifImageDecoder.readImage(GifImageDecoder.java:551)
	at sun.awt.image.GifImageDecoder.produceImage(GifImageDecoder.java:195)
	at sun.awt.image.InputStreamImageSource.doFetch(InputStreamImageSource.java:246)
	at sun.awt.image.ImageFetcher.fetchloop(ImageFetcher.java:172)
	at sun.awt.image.ImageFetcher.run(ImageFetcher.java:136)
I use Java 1.5.0_03


Please note all comments are moderated due to spam concerns. Your comment may not immediately appear once submitted.

Add a comment

Title
Body
Name
E-mail address
Website
Remember me Yes  No 
  • E-mail addresses are not publicly displayed - please leave your e-mail address if you would like to be notified when new comments are added to this blog entry (you can opt-out later).
  • Allowed HTML/XHTML tags : b, i, blockquote, br, p, pre, a href="", ul, ol, li
TrackBack : http://www.clientjava.com/blog/addTrackBack.action?entry=1093972473000