Swing's Single Threading Rule - recipe please?

Hi there,

Some dust has been kicked up with JSR-296 being worked on, and we're seeing lots SwingUtilities.invokeLater advocates piping up on their blogs.

Being from the very 'old school', and not so often delving into intense Swing-isms, I'd like to learn the "right way" of doing things, and also to which granularity these should be applied.

For reference, take a look at this blog: http://weblogs.java.net/blog/cayhorstmann/archive/2007/06/the_single_thre.html

Sadly enough, the "StillBad" example is precisely how we were taught in University long ago. Some clarification is required:

--> Which methods do we need to wrap into invokeLater blocks precisely?

from what I can gather, it seems that any function that affects GUI state needs to be wrapped as such? It sure seems a ginormous PITA to have to wrap every last "setText" in an invokeLater Runnable.... doesn't this incur a pretty considerable object instantiation overhead?

What's the "right way"?

Thanks!

Alex

[1046 byte] By [Saevena] at [2007-11-27 7:29:27]
# 1

> What's the "right way"?

[url http://java.sun.com/products/jfc/tsc/articles/threads/threads1.html#single_thread_rule]Single Thread Rule[/url]

> it seems that any function that affects GUI state needs to be wrapped as such?

[url http://java.sun.com/products/jfc/tsc/articles/threads/threads1.html#exceptions]Exceptions to the Rule[/url]

> It sure seems a ginormous PITA to have to wrap every last "setText" in an invokeLater Runnable..

Read the API, maybe setText() is one of those method that is Thread safe!

camickra at 2007-7-12 19:09:36 > top of Java-index,Desktop,Core GUI APIs...
# 2

Thanks for the response Camickr.

Considering the above, what of libraries like Spin (http://spin.sourceforge.net) and Foxtrot? These seem to highly outdo whatever invokeLater would offer, completely separating EDT tasks.

I raised the question about setText, given that it seems to be the culprit of choice in all of these examples..lest it not be a culprit!

Saevena at 2007-7-12 19:09:36 > top of Java-index,Desktop,Core GUI APIs...
# 3

> what of libraries like Spin (http://spin.sourceforge.net) and Foxtrot?

Never used them before, but I'm sure there is a certain amount of overhead involved, probably more than using an invokeLater(). I would guess it boils down to what code you think is easier to write and maintain and which is less error prone.

camickra at 2007-7-12 19:09:36 > top of Java-index,Desktop,Core GUI APIs...
# 4

So is the idea that there is no guarantee that certain methods will run off of the EDT? Or would it always be the case that it does?

I'm just a bit confused, I'm placing these:

System.out.println( "EDT " + (SwingUtilities.isEventDispatchThread() ? " YES " : "NO") );

Here and there to see if I can detect some bandits in my code, and all are checking out.

The claim is that it is something like this that would be bad, correct?

private class Test extends JFrame{

public Test(){

final JLabel label = new JLabel("...");

getContentPane().add( label );

setSize( 300, 300 );

setDefaultCloseOperation( EXIT_ON_CLOSE );

setVisible( true );

label.setText( "bad" ); // bad

}

}

Saevena at 2007-7-12 19:09:36 > top of Java-index,Desktop,Core GUI APIs...
# 5

> The claim is that it is something like this that would be bad, correct?

Yes, because the code is executing in a non EDT.

However, when code is executed in a Listener (ActionListener, MouseListener....) then you don't have to worry because the listener is invoked from the EDT.

The only time you worry is when you create a Thread yourself to remove processing from the EDT so you don't block it from responding to GUI events. Then in that case you need to worry about placing code back onto the EDT using invokeLater() or some other mechanism.

camickra at 2007-7-12 19:09:36 > top of Java-index,Desktop,Core GUI APIs...
# 6

> The claim is that it is something like this that would be bad, correct?

Yes, because the code is executing in a non EDT.

Hm?

It depends whether tha constructor is called on the EDT. Given that the class extends JFrame, it would have to be called on the EDT anyway (since it's implicitly calling the super constructor, of course). So that constructor code is absolutely fine. (Obviously setting the label text, displaying it, then setting again is odd - but perfectly viable.)

itchyscratchya at 2007-7-12 19:09:36 > top of Java-index,Desktop,Core GUI APIs...
# 7

> It depends whether tha constructor is called on the EDT.

Read the links I gave above. Invoking a constructor has nothing to do with the code being executed on the EDT or not. The key word that I take from the link is that the component must be "realized".

When simply creating a Swing component it does not matter whether the code is executed on the EDT or not. The problem only arises when you actually add the component to the GUI and it needs to be painted and respond to events. At least thats my understanding.

camickra at 2007-7-12 19:09:36 > top of Java-index,Desktop,Core GUI APIs...
# 8

Read the links I gave above.

Don't worry, I'm familiar with that page :)

I'll quote a bit and add some emphasis in bold:

"An application's GUI can often be constructed and shown in the main thread: The following typical code is safe, as long as no components (Swing or otherwise) have been realized:"

I don't think it's as clear as it could be. But the way I read this, it says that you shouldn't go constructing Swing components off the EDT once any components have been realized. The example it gives is specifically a main() method, the invocation of which is always off the EDT and before any components are realized (assuming the application doesn't call it itself).

So, I always err on the side of caution: all my Swing calls are made on the EDT and I don't try to second-guess whether any components have been realized (which, in a constructor, you wouldn't be able to predict).

Frankly, though, it's a bit beside the point: referring back to the OP's code, actually adding a component into the hierarchy in its own constructor is bad practice for precisely this reason, and several others besides :)

itchyscratchya at 2007-7-12 19:09:36 > top of Java-index,Desktop,Core GUI APIs...
# 9

Thanks for the continued discussion here guys.

actually adding a component into the hierarchy in its own constructor is bad practice for precisely this reason, and several others besides :)You're referring to the setVisible call in the component's constructor?

The Java STR page would seem to exact that no harm is done in doing so, since nothing takes place post-realization. This doesn't stand?

Saevena at 2007-7-12 19:09:36 > top of Java-index,Desktop,Core GUI APIs...
# 10

In a main method, I've never once put my initial UI constructing code, from the frame constructor to the pack()/setVisible() calls on the EDT via SwingUtilities.invokeXxx(). And I've never encountered a problem.

Once the frame is shown, that's another issue. I recently created an applet and init()/start() simply show an initial UI and then the real code kicks in via another thread, and that all uses invokeXxx() for updating the UI as the startup progresses.

Otherwise I follow the rules for using SwingUtilities, and the exceptions. (Although I've recently found that other people on my team have not been doing such... time to break out the wooden rulers.)

bsampieria at 2007-7-12 19:09:36 > top of Java-index,Desktop,Core GUI APIs...
# 11

> referring back to the OP's code,

Sorry, I wasn't paying attention. I was thinking the posted code was executing in the main() method (not the constructor), in which case you would know that a GUI hadn't yet been realized so the code was theoretically safe according to the exception given above.

But I guess there is always nothing to prevent another class with an active GUI from executing the main() method of that class, so in practice yes its always safer to make sure all code is executed from within the EDT.

camickra at 2007-7-12 19:09:36 > top of Java-index,Desktop,Core GUI APIs...
# 12

You're referring to the setVisible call in the component's constructor? The Java STR page would seem to exact that no harm is done in doing so, since nothing takes place post-realization. This doesn't stand?

Like I say, it depends on when your constructor is called. If it's called directly from main() then the setVisible() (but not the subsequent setText()) is ok.

My point is that doing this sort of thing in a constructur is A Bad Idea; because, (a) in a constructor you've no idea if you're being called at the start of the main() method or if you're being called way downstream by another bit of UI or whatever, and (b) it pre-empts what the caller is planning to do with the object - imagine creating a JPanel which went and found a component in the hierarchy and added itself - hey, I wasn't going to put it there - and whilst it's a reasonable argument that you're not likely to do much else with a frame other than display it, there may well be things you want to do before displaying it.

So, if we lose the line that realizes the component, we not only get a more usable and predictable constructor (remember polymorphism: a JFrame doesn't make itself visible when it's constructed; yours shouldn't diverge dramatically from that behaviour - it looks like a duck but it doesn't quack like a duck) but we also lose the line that causes everything downstream to be thread critical.

In a main method, I've never once put my initial UI constructing code, from the frame constructor to the pack()/setVisible() calls on the EDT via SwingUtilities.invokeXxx(). And I've never encountered a problem.

Yup, that's what the documentation is saying: that's not going to cause issues. The confusing bit here is that the OP's written a constructor that looks like a 'typical'* main() method :)

Like I say, seeing as there's only a very short and transient period where working off the EDT is valid, it's generally best to make it wholly unconfusing and do 100% of the Swing stuff on the EDT.

* in tutorials at least

itchyscratchya at 2007-7-12 19:09:36 > top of Java-index,Desktop,Core GUI APIs...
# 13

> My point is that doing this sort of thing in a

> constructur is A Bad Idea;

That is not so.

If you are writing code where you know what's going on, then you know how it's being used. And you should do the right thing based on your code.

If you are writing a library for others to use, then generally speaking, the rule should be do not assume it's thread-safe unless it says explicitly in the documentation that it is.

> So, if we lose the line that realizes the component,

> we not only get a more usable and predictable

> constructor (remember polymorphism: a JFrame doesn't

> make itself visible when it's constructed; yours

> shouldn't diverge dramatically from that behaviour -

> it looks like a duck but it doesn't quack like a

> duck) but we also lose the line that causes

> everything downstream to be thread critical.

That would be a reason to use SwingUtilities to create the JFrame subclass. You need to know what you are working with. And if you don't know, assume the worst.

> In a main method, I've never once put my initial

> UI constructing code, from the frame constructor to

> the pack()/setVisible() calls on the EDT via

> SwingUtilities.invokeXxx(). And I've never

> encountered a problem.

>

> Yup, that's what the documentation is saying: that's

> not going to cause issues. The confusing bit here is

> that the OP's written a constructor that looks like a

> 'typical'* main() method :)

>

> Like I say, seeing as there's only a very short and

> transient period where working off the EDT is valid,

> it's generally best to make it wholly unconfusing and

> do 100% of the Swing stuff on the EDT.

It's a general rule that is not bad if followed... You can't hurt yourself by following that rule. Like I said... Know what you are using.

(Granted, this doesn't mean that Sun can't change something weird in JFrame in Java 7)

bsampieria at 2007-7-12 19:09:36 > top of Java-index,Desktop,Core GUI APIs...
# 14

If you are writing code where you know what's going on, then you know how it's being used. And you should do the right thing based on your code.

True. But if you're not the only person writing the code and/or you're going to have to look at it again in 18 months, I prefer things to be as clear as possible :)

Actually - no, I disagree, I think it's plain bad practice in that the object has poor polymorphic consistency and its degree of coupling is increased. I'm sure there are exceptions but I'll stick with my fundamentalist view as a baseline ;)

itchyscratchya at 2007-7-12 19:09:36 > top of Java-index,Desktop,Core GUI APIs...
# 15

Yes... well, you usually can't go wrong with doing the "fundamentalist" thing, even if it's not strictly necessary.

What I was originally referring to (re reply #4), and not really sure if I was reading the original stuff right, had to do with constructors (class constructors) and not main methods. I would not write a UI class's constructor to try calling invokeXxx with runnables to do UI content changes within the class. I would not even check if it's running on the EDT. Maybe that's not was not what was being suggested there...

But I think the assumption has to be that the user of the class (the one calling the constructor) is calling it knowing that it's going to do some UI object creation/manipulation. In which case it's the caller's, not the class's, responsibility to make sure that's executed on the EDT. Of course, for most component classes, the constructor won't be creating a visible/realized component (it still has to be added to a container first... typically).

bsampieria at 2007-7-21 22:15:47 > top of Java-index,Desktop,Core GUI APIs...
# 16
the user of the class (the one calling the constructor) is calling it knowing that it's going to do some UI object creation/manipulationAbsolutely.
itchyscratchya at 2007-7-21 22:15:47 > top of Java-index,Desktop,Core GUI APIs...